package com.rm.zeyou.service.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.rm.zeyou.constant.CommonConstants;
import com.rm.zeyou.constant.NumberConstants;
import com.rm.zeyou.constant.OrderConstants;
import com.rm.zeyou.constant.PayConstants;
import com.rm.zeyou.entity.*;
import com.rm.zeyou.exception.ErrorCodeException;
import com.rm.zeyou.exception.ErrorCodeExceptionEnum;
import com.rm.zeyou.mapper.*;
import com.rm.zeyou.pay.alipay.entity.AlipayEntity;
import com.rm.zeyou.pay.alipay.service.AlipayService;
import com.rm.zeyou.pay.wxpay.entity.WxPayEntity;
import com.rm.zeyou.pay.wxpay.service.WechatPayService;
import com.rm.zeyou.pay.wxpay.vo.SettleInfo;
import com.rm.zeyou.pay.wxpay.vo.WeChatCreateOrderVO;
import com.rm.zeyou.pay.wxpay.vo.WeChatRefundReturnVO;
import com.rm.zeyou.pay.wxpay.vo.WeChatRefundVO;
import com.rm.zeyou.response.ApiRestResponse;
import com.rm.zeyou.service.RefundOrderService;
import com.rm.zeyou.service.TechnicianConsumeDetailService;
import com.rm.zeyou.service.TechnicianItemOrderService;
import com.rm.zeyou.service.UserItemOrderService;
import com.rm.zeyou.util.address.AddressUtil;
import com.rm.zeyou.util.address.WSSsdrAddress;
import com.rm.zeyou.util.check.CheckEmptyUtil;
import com.rm.zeyou.util.date.DateUtils;
import com.rm.zeyou.util.distance.MathDistanceUtil;
import com.rm.zeyou.util.gaode.GaoDeUtil;
import com.rm.zeyou.util.random.RandomUtils;
import com.rm.zeyou.util.sms.SmsService;
import com.rm.zeyou.util.websocket.server.WebSocketServer;
import com.rm.zeyou.util.websocket.server.vo.MessageVo;
import com.rm.zeyou.vo.request.*;
import com.rm.zeyou.vo.response.*;
import com.rm.zeyou.voice.VoiceUtil;
import com.rm.zeyou.voice.vo.request.VoiceNotifyVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 用户订单表 服务实现类
 * </p>
 *
 * @author YanYang
 * @since 2025-03-12 15:55:09
 */
@Slf4j
@Service
public class UserItemOrderServiceImpl extends ServiceImpl<UserItemOrderMapper, UserItemOrder> implements UserItemOrderService {

    @Resource
    private UserItemOrderMapper userItemOrderMapper;
    @Resource
    private UserCouponMapper userCouponMapper;
    @Resource
    private ItemMapper itemMapper;
    @Resource
    private ItemSpecsMapper itemSpecsMapper;
    @Resource
    private UserMemberMapper userMemberMapper;
    @Resource
    private MemberConfigMapper memberConfigMapper;
    @Resource
    private TechnicianMapper technicianMapper;
    @Resource
    private TechnicianTimeMapper technicianTimeMapper;
    @Resource
    private CouponConfigMapper couponConfigMapper;
    @Resource
    private UserAddressMapper userAddressMapper;
    @Resource
    private GaoDeUtil gaoDeUtil;
    @Resource
    private CityFareConfigMapper cityFareConfigMapper;
    @Resource
    private CityFareGlobalConfigMapper cityFareGlobalConfigMapper;
    @Resource
    private TechnicianItemOrderMapper technicianItemOrderMapper;
    @Resource
    private MessageMapper messageMapper;
    @Resource
    private UserMapper userMapper;
    @Resource
    private UserConsumeDetailMapper userConsumeDetailMapper;
    @Resource
    private UserAppraiseMapper userAppraiseMapper;
    @Resource
    private TechnicianConsumeDetailMapper technicianConsumeDetailMapper;
    @Resource
    private SmsService smsService;
    @Resource
    private WechatPayService wechatPayService;
    @Resource
    private SmsTemplateConfigMapper smsTemplateConfigMapper;
    @Resource
    private TechnicianConsumeDetailService technicianConsumeDetailService;
    @Resource
    private ShareConfigMapper shareConfigMapper;
    @Resource
    private SalesmanMapper salesmanMapper;
    @Resource
    private SalesmanConsumeDetailMapper salesmanConsumeDetailMapper;
    @Resource
    private ChannelMerchantsMapper channelMerchantsMapper;
    @Resource
    private ChannelConsumeDetailMapper channelConsumeDetailMapper;
    @Resource
    private BrokerMapper brokerMapper;
    @Resource
    private BrokerConsumeDetailMapper brokerConsumeDetailMapper;
    @Resource
    private ClockItemSpecsMapper clockItemSpecsMapper;
    @Resource
    private ClockItemMapper clockItemMapper;
    @Resource
    private OrderDictConfigMapper orderDictConfigMapper;
    @Resource
    private VoiceUtil voiceUtil;
    @Resource
    private VoiceTemplateConfigMapper voiceTemplateConfigMapper;
    @Resource
    private WxPayEntity wxPayEntity;
    @Resource
    private AlipayService alipayService;
    @Resource
    private AlipayEntity alipayEntity;
    @Resource
    private BackendOrderNotifyMapper backendOrderNotifyMapper;
    @Resource
    private DictConfigMapper dictConfigMapper;
    @Resource
    private RefundOrderService refundOrderService;
    @Resource
    private TechnicianItemOrderService technicianItemOrderService;

    @Override
    public ApiRestResponse<CreateOrderResponseVo> createOrderDetail(Long userId, CreateOrderVo createOrderVo) throws ParseException {
        CreateOrderResponseVo vo = new CreateOrderResponseVo();
        //项目费
        BigDecimal itemTotalPrice = BigDecimal.ZERO;
        //开通会员金额
        BigDecimal openVipPrice = BigDecimal.ZERO;
        //共优惠金额
        BigDecimal discountTotalPrice = BigDecimal.ZERO;
        //车费
        BigDecimal carFare = BigDecimal.ZERO;
        //支付金额
        BigDecimal payTotalPrice = BigDecimal.ZERO;

        //判断是否是会员
        int isVip = userMemberMapper.selectCount(new LambdaQueryWrapper<UserMember>().eq(UserMember::getUserId, userId)).intValue();
        vo.setIsVip(isVip);
        CreateOrderResponseVo item = sumItem(createOrderVo.getItemSpecsId(), createOrderVo.getItemNum(), isVip, createOrderVo.getIsOpenVip());
        vo.setItemMainPicture(item.getItemMainPicture());
        vo.setItemSpecsName(item.getItemSpecsName());
        //项目价格
        vo.setItemSpecsPrice(item.getItemSpecsPrice());
        //套餐原价
        vo.setItemPrice(item.getItemPrice());
        //套餐优惠价
        vo.setItemVipPrice(item.getItemVipPrice());
        //套餐立省金额
        vo.setItemDiscountPrice(item.getItemDiscountPrice());
        vo.setItemNum(item.getItemNum());
        //查询技师
        Technician technician = technicianMapper.selectById(createOrderVo.getTid());
        vo.setTechnicianAvatar(technician.getTechnicianAvatar());
        vo.setTechnicianName(technician.getTechnicianName());
        if (userId.equals(technician.getUserId())) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.USER_TECHNICIAN_ONE);
        }
        TechnicianTime technicianTime = technicianTimeMapper.selectById(createOrderVo.getTechnicianTimeId());
        if (!CheckEmptyUtil.isEmpty(technicianTime)) {
            vo.setTechnicianTime(technicianTime.getDay() + " " + technicianTime.getTime());
        } else {
            SelectLatelyTime selectLatelyTime = technicianTimeMapper.selectLatelyTime(technician.getId(), DateUtil.today().substring(DateUtil.today().indexOf("-") + 1), item.getItemTime() + 30);
            if (!CheckEmptyUtil.isEmpty(selectLatelyTime)) {
                vo.setTechnicianTime(selectLatelyTime.getDay() + " " + selectLatelyTime.getTime());
                vo.setTechnicianTimeId(selectLatelyTime.getId());
                createOrderVo.setTechnicianTimeId(selectLatelyTime.getId());
            } else {
                String torm = DateUtil.format(DateUtil.offsetDay(new Date(), 1), "yyyy-MM-dd");
                SelectLatelyTime selectTormLatelyTime = technicianTimeMapper.selectTormLatelyTime(technician.getId(), torm.substring(torm.indexOf("-") + 1));
                if (!CheckEmptyUtil.isEmpty(selectTormLatelyTime)) {
                    vo.setTechnicianTime(selectTormLatelyTime.getDay() + " " + selectTormLatelyTime.getTime());
                    vo.setTechnicianTimeId(selectTormLatelyTime.getId());
                    createOrderVo.setTechnicianTimeId(selectTormLatelyTime.getId());
                }
            }
        }

        CreateOrderResponseVo vip = sumVip(isVip, item.getItemPrice(), item.getItemVipPrice());
        vo.setVipId(vip.getVipId());
        vo.setVipName(vip.getVipName());
        //会员原价
        vo.setVipPrice(vip.getVipPrice());
        //会员折扣价
        vo.setVipVipPrice(vip.getVipVipPrice());
        //会员立省
        vo.setVipDiscountPrice(vip.getVipDiscountPrice());


        CreateOrderResponseVo coupon = sumCoupon(createOrderVo.getIsUserCoupon(), createOrderVo.getUserCouponId());
        vo.setCouponName(coupon.getCouponName());
        //优惠券立省金额
        vo.setCouponDiscountPrice(coupon.getCouponDiscountPrice());

        CreateOrderResponseVo address = sumAddress(createOrderVo.getAddressId());
        vo.setAddressName(address.getAddressName());
        vo.setAddressTel(address.getAddressTel());
        vo.setAddress(address.getAddress());

        if (createOrderVo.getIsOpenVip().equals(NumberConstants.ONE_CONSTANTS)) {
            openVipPrice = vip.getVipVipPrice();
        }
        vo.setOpenVipPrice(openVipPrice);
        //计算车费
        CreateOrderResponseVo sumCarFare = sumCarFare(createOrderVo.getAddressId(), technician, createOrderVo.getTechnicianTimeId());
        vo.setDistance(sumCarFare.getDistance());
        vo.setCarFare(sumCarFare.getCarFare());
        carFare = sumCarFare.getCarFare();
        discountTotalPrice = item.getItemDiscountPrice().add(coupon.getCouponDiscountPrice());
        vo.setDiscountTotalPrice(discountTotalPrice);
        itemTotalPrice = item.getItemSpecsPrice();
        payTotalPrice = openVipPrice.add(carFare).add(itemTotalPrice).subtract(coupon.getCouponDiscountPrice());
        vo.setPayTotalPrice(payTotalPrice);
        return ApiRestResponse.success(vo);
    }

    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public synchronized ApiRestResponse createOrder(User user, CreateOrderVo createOrderVo) throws Exception {
        //判断用户地址
        UserAddress address = userAddressMapper.selectById(createOrderVo.getAddressId());
        if (CheckEmptyUtil.isEmpty(address)) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.ADDRESS_ERROR);
        }
        //查询技师是否在线
        Technician technician = technicianMapper.selectById(createOrderVo.getTid());
        if (technician.getIsOnline().equals(NumberConstants.ZERO_CONSTANTS)) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.TECHNICIAN_NOT_ONLINE);
        }
        if (user.getId().equals(technician.getUserId())) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.USER_TECHNICIAN_ONE);
        }
        TechnicianTime technicianTime = technicianTimeMapper.selectById(createOrderVo.getTechnicianTimeId());
        if (CheckEmptyUtil.isEmpty(technicianTime)) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.SERVICE_TIME_EMPTY);
        }
        ItemSpecs itemSpecs = itemSpecsMapper.selectById(createOrderVo.getItemSpecsId());
        Item item = !CheckEmptyUtil.isEmpty(itemSpecs) ? itemMapper.selectById(itemSpecs.getItemId()) : itemMapper.selectById(createOrderVo.getItemSpecsId());


        //只能选择当前时间30分钟之后的时间
        parseStringToDate(technicianTime.getDay(), technicianTime.getTime());
        //先查询该时间技师是否有正在进行中的的订单
        // 如果没有正常下单
        // 如果有 算出正常完成项目后的时间  与用户选择的时间进行比较 如果订单完成时间小于用户选择的时间 则为不可选
        TechnicianItemOrder technicianItemOrder = technicianItemOrderMapper.selectOneTakingOrder(createOrderVo.getTid());
        if (!CheckEmptyUtil.isEmpty(technicianItemOrder)) {
            String serviceTime = technicianItemOrder.getServiceTime();
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
            //服务完成时间
            DateTime itemFinshTime = sumOrderFinishTime(simpleDateFormat, serviceTime, technicianItemOrder.getItemTime() * technicianItemOrder.getOrderNum());
            //选择时间
            String choseTime1 = DateUtil.thisYear() + "-" + technicianTime.getDay() + " " + technicianTime.getTime();
            Date choseTime = simpleDateFormat.parse(choseTime1);
            if (itemFinshTime.isAfter(choseTime)) {
                throw new ErrorCodeException(ErrorCodeExceptionEnum.SERVICE_TIME_NOT_USE);
            }
        }

        //计算费用
        CreateOrderResponseVo data = createOrderDetail(user.getId(), createOrderVo).getData();
        //项目费
        BigDecimal itemTotalPrice = data.getItemSpecsPrice();
        //开通会员金额
        BigDecimal openVipPrice = data.getOpenVipPrice();
        //共优惠金额
        BigDecimal discountTotalPrice = data.getDiscountTotalPrice();
        //车费
        BigDecimal carFare = data.getCarFare();
        //支付金额
        BigDecimal payTotalPrice = data.getPayTotalPrice();
        BigDecimal distance = data.getDistance();

        String orderNo = RandomUtils.getOrderNo();
        UserItemOrder insertUserItemOrder = new UserItemOrder();
        insertUserItemOrder.setOrderNo(orderNo);
        insertUserItemOrder.setUserId(user.getId());
        insertUserItemOrder.setTid(createOrderVo.getTid());
        insertUserItemOrder.setItemId(item.getId());
        insertUserItemOrder.setItemSpecsId(createOrderVo.getItemSpecsId());
        insertUserItemOrder.setItemName(!CheckEmptyUtil.isEmpty(itemSpecs) ? itemSpecs.getItemSpecsName() : item.getItemName());
        insertUserItemOrder.setItemPicture(item.getItemMainPicture());
        insertUserItemOrder.setItemTime(!CheckEmptyUtil.isEmpty(itemSpecs) ? itemSpecs.getItemSpecsTime() * createOrderVo.getItemNum() : item.getItemTime() * createOrderVo.getItemNum());
        insertUserItemOrder.setAddressId(address.getId());
        insertUserItemOrder.setAddressUserName(address.getAddressName());
        insertUserItemOrder.setAddressTel(address.getAddressTel());
        insertUserItemOrder.setAddressDetail(address.getAddress() + address.getAddressDetails());
        insertUserItemOrder.setServiceTime(technicianTime.getYear() + "-" + technicianTime.getDay() + " " + technicianTime.getTime());
        insertUserItemOrder.setNeedPayPrice(payTotalPrice);
        insertUserItemOrder.setOrderTotalPrice(payTotalPrice);
        insertUserItemOrder.setOrderItemPrice(itemTotalPrice);
        insertUserItemOrder.setOrderFarePrice(carFare);
        insertUserItemOrder.setDiscountPrice(discountTotalPrice);
        insertUserItemOrder.setIsUserCoupon(createOrderVo.getIsUserCoupon());
        insertUserItemOrder.setUserCouponId(createOrderVo.getUserCouponId());
        insertUserItemOrder.setUserCouponPrice(sumCoupon(createOrderVo.getIsUserCoupon(), createOrderVo.getUserCouponId()).getCouponDiscountPrice());
        insertUserItemOrder.setPlaceOrderTime(new Date());
        insertUserItemOrder.setOrderNum(createOrderVo.getItemNum());
        insertUserItemOrder.setIsOpenMembership(createOrderVo.getIsOpenVip());
        insertUserItemOrder.setOpenMemberId(createOrderVo.getVipId());
        insertUserItemOrder.setOpenMemberPrice(openVipPrice);
        insertUserItemOrder.setDistance(distance);
        insertUserItemOrder.setPayType(createOrderVo.getPayType());
        //insertUserItemOrder.setLeaveAddress(gaoDeUtil.ReGeoCode(technician.getLongitude() + "," + technician.getLatitude()));
        insertUserItemOrder.setModeTravel(createOrderVo.getModeTravel());
        insertUserItemOrder.setOrderRemark(createOrderVo.getOrderRemark());
        insertUserItemOrder.setOrderStatus(OrderConstants.ORDER_STATUS_PENDING_PAYMENT);
        userItemOrderMapper.insert(insertUserItemOrder);


        TechnicianItemOrder insertTechnicianItemOrder = new TechnicianItemOrder();
        insertTechnicianItemOrder.setOrderNo(orderNo);
        insertTechnicianItemOrder.setUserId(user.getId());
        insertTechnicianItemOrder.setTid(createOrderVo.getTid());
        insertTechnicianItemOrder.setItemId(item.getId());
        insertTechnicianItemOrder.setItemSpecsId(createOrderVo.getItemSpecsId());
        insertTechnicianItemOrder.setItemName(!CheckEmptyUtil.isEmpty(itemSpecs) ? itemSpecs.getItemSpecsName() : item.getItemName());
        insertTechnicianItemOrder.setItemPicture(item.getItemMainPicture());
        insertTechnicianItemOrder.setItemTime(!CheckEmptyUtil.isEmpty(itemSpecs) ? itemSpecs.getItemSpecsTime() * createOrderVo.getItemNum() : item.getItemTime() * createOrderVo.getItemNum());
        insertTechnicianItemOrder.setAddressId(address.getId());
        insertTechnicianItemOrder.setAddressUserName(address.getAddressName());
        insertTechnicianItemOrder.setAddressTel(address.getAddressTel());
        insertTechnicianItemOrder.setAddressDetail(address.getAddress() + address.getAddressDetails());
        insertTechnicianItemOrder.setServiceTime(technicianTime.getYear() + "-" + technicianTime.getDay() + " " + technicianTime.getTime());
        insertTechnicianItemOrder.setNeedPayPrice(payTotalPrice);
        insertTechnicianItemOrder.setOrderTotalPrice(payTotalPrice);
        insertTechnicianItemOrder.setOrderItemPrice(itemTotalPrice);
        insertTechnicianItemOrder.setOrderFarePrice(carFare);
        insertTechnicianItemOrder.setDiscountPrice(discountTotalPrice);
        insertTechnicianItemOrder.setIsUserCoupon(createOrderVo.getIsUserCoupon());
        insertTechnicianItemOrder.setUserCouponId(createOrderVo.getUserCouponId());
        insertTechnicianItemOrder.setUserCouponPrice(sumCoupon(createOrderVo.getIsUserCoupon(), createOrderVo.getUserCouponId()).getCouponDiscountPrice());
        insertTechnicianItemOrder.setPlaceOrderTime(new Date());
        insertTechnicianItemOrder.setOrderNum(createOrderVo.getItemNum());
        insertTechnicianItemOrder.setIsOpenMembership(createOrderVo.getIsOpenVip());
        insertTechnicianItemOrder.setOpenMemberId(createOrderVo.getVipId());
        insertTechnicianItemOrder.setOpenMemberPrice(openVipPrice);
        insertTechnicianItemOrder.setDistance(distance);
        insertTechnicianItemOrder.setPayType(createOrderVo.getPayType());
        //insertTechnicianItemOrder.setLeaveAddress(gaoDeUtil.ReGeoCode(technician.getLongitude() + "," + technician.getLatitude()));
        insertTechnicianItemOrder.setOrderRemark(createOrderVo.getOrderRemark());
        insertTechnicianItemOrder.setModeTravel(createOrderVo.getModeTravel());
        insertTechnicianItemOrder.setOrderStatus(OrderConstants.ORDER_STATUS_PENDING_PAYMENT);
        technicianItemOrderMapper.insert(insertTechnicianItemOrder);

        Message message = new Message();
        message.setUserId(user.getId());
        message.setOrderNo(orderNo);
        message.setMessageTitle("您有一条待支付订单");
        message.setMessageComment("您有一条待支付订单");
        messageMapper.insert(message);

        PayOrderRequestVo request = new PayOrderRequestVo();
        request.setUser(user);
        request.setOrderNo(orderNo);
        request.setPayType(createOrderVo.getPayType());
        request.setWxType(createOrderVo.getWxType());
        request.setReturnUrl(createOrderVo.getReturnUrl());
        request.setQuitUrl(createOrderVo.getQuitUrl());
        return payOrder(request);
    }

    /**
     * 支付订单
     *
     * @param requestVo
     * @return
     * @throws ParseException
     */
    @Override
    public ApiRestResponse payOrder(PayOrderRequestVo requestVo) throws Exception {
        User user = requestVo.getUser();
        //UserItemOrder userItemOrder = userItemOrderMapper.selectOne(new LambdaQueryWrapper<UserItemOrder>()
        //        .eq(UserItemOrder::getOrderNo, requestVo.getOrderNo()));
        UserItemOrder userItemOrder = userItemOrderMapper.selectOneByOrderNo(requestVo.getOrderNo());

        if (!userItemOrder.getOrderStatus().equals(OrderConstants.ORDER_STATUS_PENDING_PAYMENT)) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.ORDER_IS_PAY);
        }

        if (requestVo.getPayType().equals(PayConstants.BALANCE)) {
            //余额支付
            if (user.getUserBalance().compareTo(BigDecimal.ZERO) <= 0 || userItemOrder.getNeedPayPrice().compareTo(user.getUserBalance()) > 0) {
                throw new ErrorCodeException(ErrorCodeExceptionEnum.BALANCE_NOT_ENOUGH);
            }
            //扣除用户余额
            //添加消费记录
            //修改订单状态
            //删除系统消息
            //修改技师时间状态
            Integer subBalance = userMapper.subBalance(user.getId(), userItemOrder.getNeedPayPrice());
            if (subBalance == 0) {
                throw new ErrorCodeException(ErrorCodeExceptionEnum.ABNORMAL_OPERATION);
            }
            UserConsumeDetail userConsumeDetail = new UserConsumeDetail();
            userConsumeDetail.setUserId(user.getId());
            userConsumeDetail.setOrderNo(requestVo.getOrderNo());
            userConsumeDetail.setConsumptionPrice(userItemOrder.getNeedPayPrice());
            userConsumeDetail.setConsumptionType(CommonConstants.CONSUMPTION_REDUCE);
            userConsumeDetail.setConsumptionDescribe("购买" + userItemOrder.getItemName());
            userConsumeDetailMapper.insert(userConsumeDetail);

            updateOrder(userItemOrder.getOrderNo(), requestVo.getPayType());


            return ApiRestResponse.success();
        } else if (requestVo.getPayType().equals(PayConstants.WX)) {
            if (requestVo.getWxType().equals(PayConstants.JSAPI_TYPE)) {
                if (CheckEmptyUtil.isEmpty(user.getOpenId())) {
                    throw new ErrorCodeException(ErrorCodeExceptionEnum.NOT_BIND_WX);
                }
            }
            //微信支付
            WeChatCreateOrderVO createOrderVO = new WeChatCreateOrderVO();
            createOrderVO.setPayType(requestVo.getWxType());
            createOrderVO.setTotalPrice(userItemOrder.getNeedPayPrice().multiply(new BigDecimal(100)));
            createOrderVO.setOutTradeNo(requestVo.getOrderNo());
            createOrderVO.setDescription("支付" + userItemOrder.getItemName());
            createOrderVO.setNotifyUrl(wxPayEntity.ProjectIP + "/api/wechat/notify");
            createOrderVO.setOpenId(userMapper.selectById(user.getId()).getOpenId());
            SettleInfo settleInfo = new SettleInfo();
            settleInfo.setProfit_sharing(false);
            createOrderVO.setSettleInfo(settleInfo);
            log.info("微信支付入参数：[{}]", createOrderVO);
            Map<String, String> order = wechatPayService.createOrder(createOrderVO);
            return ApiRestResponse.success(order);

        } else if (requestVo.getPayType().equals(PayConstants.ZFB)) {
            if (!CheckEmptyUtil.isEmpty(userItemOrder.getZfbPayParam())) {
                return ApiRestResponse.success(userItemOrder.getZfbPayParam());
            } else {
                //支付宝支付
                String pay = alipayService.pay(requestVo.getWxType(), "支付" + userItemOrder.getItemName(), requestVo.getOrderNo(), userItemOrder.getNeedPayPrice().toString(), requestVo.getReturnUrl(), requestVo.getQuitUrl(), alipayEntity.getNotifyIp() + "/api/alipay/notify");
                userItemOrderMapper.insertZfbInfo(userItemOrder.getOrderNo(), pay);
                return ApiRestResponse.success(pay);
            }

        } else {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.PAY_TYPE_ERROR);
        }
    }

    /**
     * 修改订单状态
     * 删除系统消息
     * 修改技师时间状态
     *
     * @param orderNo
     * @param payType
     * @Date 2025 3月 13 11:06
     */
    @Override
    public void updateOrder(String orderNo, String payType) throws Exception {
        //UserItemOrder userItemOrder = userItemOrderMapper.selectOne(new LambdaQueryWrapper<UserItemOrder>()
        //        .eq(UserItemOrder::getOrderNo, orderNo));
        UserItemOrder userItemOrder = userItemOrderMapper.selectOneByOrderNo(orderNo);

        userItemOrder.setOrderStatus(OrderConstants.ORDER_STATUS_PENDING_ACCEPTANCE);
        userItemOrder.setPayType(payType);
        userItemOrder.setPayTime(new Date());
        userItemOrder.setZfbPayParam(null);
        userItemOrderMapper.updateById(userItemOrder);
        TechnicianItemOrder technicianItemOrder = technicianItemOrderMapper.selectOne(new LambdaQueryWrapper<TechnicianItemOrder>().eq(TechnicianItemOrder::getOrderNo, orderNo));
        technicianItemOrder.setOrderStatus(OrderConstants.ORDER_STATUS_PENDING_ACCEPTANCE);
        technicianItemOrder.setPayType(payType);
        technicianItemOrder.setPayTime(new Date());
        technicianItemOrderMapper.updateById(technicianItemOrder);


        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        //服务时间
        Date serviceTime = simpleDateFormat.parse(userItemOrder.getServiceTime());
        //项目完成时间
        DateTime orderFinshTime = sumOrderFinishTime(simpleDateFormat, userItemOrder.getServiceTime(), userItemOrder.getItemTime());
        //更新服务时间 状态为已被预约
        technicianTimeMapper.updateTimeToTwo(userItemOrder.getTid(), simpleDateFormat.format(serviceTime));
        //更新服务时间 到 服务结束时间+1小时 之内的时间为不可约状态
        technicianTimeMapper.updateTimeToOne(userItemOrder.getTid(), simpleDateFormat.format(serviceTime), simpleDateFormat.format(orderFinshTime));

        //是否开通会员
        if (userItemOrder.getIsOpenMembership().equals(NumberConstants.ONE_CONSTANTS)) {
            MemberConfig memberConfig = memberConfigMapper.selectById(userItemOrder.getOpenMemberId());
            payVip(userItemOrder.getUserId(), memberConfig.getMemberType(), memberConfig.getEffectDay());
        }

        //修改优惠券状态
        if (userItemOrder.getIsUserCoupon().equals(NumberConstants.ONE_CONSTANTS)) {
            userCouponMapper.updateUserCouponStatus(userItemOrder.getUserCouponId(), CommonConstants.USERCOUPON_USER);
        }

        Technician technician = technicianMapper.selectById(userItemOrder.getTid());
        User user = userMapper.selectById(userItemOrder.getUserId());
        BackendOrderNotify backendOrderNotify = new BackendOrderNotify();
        backendOrderNotify.setOrderNo(technicianItemOrder.getOrderNo());
        backendOrderNotify.setTechnicianName(technician.getTechnicianName());
        backendOrderNotify.setNotifyType(NumberConstants.ZERO_CONSTANTS);
        backendOrderNotify.setUserName(user.getUserNikeName());
        backendOrderNotifyMapper.insert(backendOrderNotify);

        String backendOrderTone = dictConfigMapper.selectValue("backend_order_tone");

        MessageVo messageVo = new MessageVo();
        messageVo.setMessage("你有一笔的新订单, 请及时联系技师处理");
        messageVo.setOrderNo(technicianItemOrder.getOrderNo());
        messageVo.setNotifyTime(new Date());
        messageVo.setType(NumberConstants.ZERO_CONSTANTS);
        messageVo.setVoiceUrl(backendOrderTone);
        //websocket发送消息到后台
        new WebSocketServer().appointSending(JSON.toJSONString(messageVo), "0");

        String technicianPlaceOrderTone = dictConfigMapper.selectValue("technician_place_order_tone");
        MessageVo technicianPlaceOrderMessage = new MessageVo();
        technicianPlaceOrderMessage.setMessage("你有一笔的新订单, 请及时处理");
        technicianPlaceOrderMessage.setOrderNo(technicianItemOrder.getOrderNo());
        technicianPlaceOrderMessage.setNotifyTime(new Date());
        technicianPlaceOrderMessage.setType(NumberConstants.THREE_CONSTANTS);
        technicianPlaceOrderMessage.setVoiceUrl(technicianPlaceOrderTone);
        //websocket发送消息到技师
        new WebSocketServer().appointSending(JSON.toJSONString(technicianPlaceOrderMessage), userItemOrder.getTid().toString());

        //通知技师
        voiceTechnician(userItemOrder.getTid(), voiceTemplateConfigMapper.selectOneData("take_order"), userItemOrder.getOrderNo());

        String templateCode = smsTemplateConfigMapper.selectOneData("take_order_notify");
        //给技师发短信
        smsService.orderSendSms(technician.getTechnicianTel(), technician.getTechnicianName(), templateCode);

        //给用户发短信

        String userTemplateCode = smsTemplateConfigMapper.selectOneData("place_order_notify");
        smsService.orderSendSms(userItemOrder.getAddressTel(), user.getUserNikeName(), userTemplateCode);

        //更新项目销量
        itemMapper.updateSales(userItemOrder.getItemId(), userItemOrder.getOrderNum());
        //technicianMapper.updateSales(userItemOrder.getTid(), userItemOrder.getOrderNum());
        //删除待支付消息
        messageMapper.deleteMessage(orderNo);

    }

    /**
     * 语音通知技师
     *
     * @param tid
     * @param templateId
     * @throws Exception
     * @Date 2025 4月 08 14:08
     */
    private void voiceTechnician(Long tid, String templateId, String orderNo) throws Exception {
        VoiceNotifyVo voiceNotifyVo = new VoiceNotifyVo();
        Technician technician = technicianMapper.selectById(tid);

        voiceNotifyVo.setTid(technician.getId());
        voiceNotifyVo.setCalleeNumber(technician.getTechnicianTel());
        voiceNotifyVo.setTemplateId(templateId);
        voiceNotifyVo.setOrderNo(orderNo);
        voiceUtil.voiceNotify(voiceNotifyVo);
    }

    /**
     * 购买会员添加会员
     *
     * @param userId
     * @param memberType
     * @param ffectDay
     * @Date 2025 3月 13 11:58
     */
    @Override
    public void payVip(Long userId, Integer memberType, Integer ffectDay) {
        //添加会员
        UserMember userMember = userMemberMapper.selectOne(new LambdaQueryWrapper<UserMember>().eq(UserMember::getUserId, userId));
        if (CheckEmptyUtil.isEmpty(userMember)) {
            UserMember insertUserMember = new UserMember();
            insertUserMember.setUserId(userId);
            insertUserMember.setMemberType(memberType);
            insertUserMember.setExpiryTime(DateUtil.offsetDay(new Date(), ffectDay));
            userMemberMapper.insert(insertUserMember);
        } else {
            //修改
            if (userMember.getMemberType() < memberType) {
                userMember.setMemberType(memberType);
            }
            userMember.setExpiryTime(DateUtil.offsetDay(userMember.getExpiryTime(), ffectDay));
            userMemberMapper.updateById(userMember);
        }
    }

    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public ApiRestResponse cancelOrder(User user, String orderNo) throws Exception {
        //UserItemOrder userItemOrder = userItemOrderMapper.selectOne(new LambdaQueryWrapper<UserItemOrder>()
        //        .eq(UserItemOrder::getOrderNo, orderNo));
        UserItemOrder userItemOrder = userItemOrderMapper.selectOneByOrderNo(orderNo);

        if (CheckEmptyUtil.isEmpty(userItemOrder)) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.ORDER_EMPTY);
        }
        if (!userItemOrder.getOrderStatus().equals(OrderConstants.ORDER_STATUS_PENDING_PAYMENT)) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.CANT_CANCEL_ORDER);
        }
        //修改订单状态
        userItemOrder.setOrderStatus(OrderConstants.ORDER_STATUS_CANCELLED);
        userItemOrderMapper.updateById(userItemOrder);
        TechnicianItemOrder technicianItemOrder = technicianItemOrderMapper.selectOne(new LambdaQueryWrapper<TechnicianItemOrder>().eq(TechnicianItemOrder::getOrderNo, orderNo));
        technicianItemOrder.setOrderStatus(OrderConstants.ORDER_STATUS_CANCELLED);
        int i = technicianItemOrderMapper.updateById(technicianItemOrder);

        //通知技师
        //voiceTechnician(userItemOrder.getTid(), voiceTemplateConfigMapper.selectOneData("order_cancel"), userItemOrder.getOrderNo());
        return ApiRestResponse.success(i);
    }

    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public ApiRestResponse userCancelOrder(User user, String orderNo) throws Exception {
        UserItemOrder userItemOrder = userItemOrderMapper.selectOneByOrderNo(orderNo);

        if (CheckEmptyUtil.isEmpty(userItemOrder)) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.ORDER_EMPTY);
        }
        if (!userItemOrder.getOrderStatus().equals(OrderConstants.ORDER_STATUS_PENDING_ACCEPTANCE)) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.CANT_CANCEL_ORDER);
        }


        //修改订单状态
        userItemOrder.setOrderStatus(OrderConstants.ORDER_STATUS_CANCELLED);
        userItemOrderMapper.updateById(userItemOrder);
        TechnicianItemOrder technicianItemOrder = technicianItemOrderMapper.selectOne(new LambdaQueryWrapper<TechnicianItemOrder>().eq(TechnicianItemOrder::getOrderNo, orderNo));
        technicianItemOrder.setOrderStatus(OrderConstants.ORDER_STATUS_CANCELLED);
        technicianItemOrder.setCancelTime(new Date());
        int i = technicianItemOrderMapper.updateById(technicianItemOrder);

        //退款
        Map<String, BigDecimal> map = refundOrderService.sumRefundPrice(userItemOrder);
        BigDecimal canRefundPrice = map.get("refundPrice");


        //通知技师
        voiceTechnician(userItemOrder.getTid(), voiceTemplateConfigMapper.selectOneData("order_cancel"), userItemOrder.getOrderNo());

        //将钱退给用户
        technicianItemOrderService.refundUser(technicianItemOrder, canRefundPrice);
        return ApiRestResponse.success(i);
    }

    @Override
    public ApiRestResponse<PageInfo<SelectUserItemOrderListResponseVo>> selectUserItemOrderList(Long userId, SelectUserItemOrderListVo requestVo) {
        PageHelper.startPage(requestVo.getPageNum(), requestVo.getPageSize());
        List<SelectUserItemOrderListResponseVo> userItemOrderListResponseVos = userItemOrderMapper.selectListByType(userId, requestVo.getType());
        if (CheckEmptyUtil.isEmpty(userItemOrderListResponseVos)) {
            return ApiRestResponse.success(new PageInfo<>(Collections.emptyList()));
        }

        List<String> orderNos = userItemOrderListResponseVos.stream()
                .map(SelectUserItemOrderListResponseVo::getOrderNo)
                .collect(Collectors.toList());

        // 批量查询升级订单
        List<UserItemOrder> upgradeOrders = userItemOrderMapper.selectList(new LambdaQueryWrapper<UserItemOrder>()
                .in(UserItemOrder::getPartnerOrderNo, orderNos)
                .eq(UserItemOrder::getUserId, userId)
                .eq(UserItemOrder::getOrderType, NumberConstants.TWO_CONSTANTS)
                .eq(UserItemOrder::getOrderStatus, OrderConstants.ORDER_STATUS_UPGRADES_NOT_PAID));

        // 批量查询加钟订单
        List<UserItemOrder> bellOrders = userItemOrderMapper.selectList(new LambdaQueryWrapper<UserItemOrder>()
                .in(UserItemOrder::getPartnerOrderNo, orderNos)
                .eq(UserItemOrder::getUserId, userId)
                .eq(UserItemOrder::getOrderType, NumberConstants.ONE_CONSTANTS)
                .eq(UserItemOrder::getOrderStatus, OrderConstants.ORDER_STATUS_BELL_NOT_PAID));

        // 构建状态映射
        Map<String, Integer> orderStatusMap = new HashMap<>();
        upgradeOrders.forEach(order -> orderStatusMap.put(order.getPartnerOrderNo(), OrderConstants.ORDER_STATUS_UPGRADES_NOT_PAID));
        bellOrders.forEach(order -> orderStatusMap.put(order.getPartnerOrderNo(), OrderConstants.ORDER_STATUS_BELL_NOT_PAID));

        // 设置订单状态
        userItemOrderListResponseVos.forEach(vo -> {
            Integer status = orderStatusMap.get(vo.getOrderNo());
            if (status != null) {
                vo.setOrderStatus(status);
            }
        });

        PageInfo<SelectUserItemOrderListResponseVo> pageInfo = new PageInfo<>(userItemOrderListResponseVos);
        return ApiRestResponse.success(pageInfo);
    }

    @Override
    public ApiRestResponse<SelectUserItemOrderDetailResponseVo> selectUserItemOrderDetail(Long userId, String orderNo) {
        SelectUserItemOrderDetailResponseVo userItemOrderDetail = userItemOrderMapper.selectOrderDetail(userId, orderNo);
        if (userItemOrderDetail.getIsUseCoupon().equals(NumberConstants.ONE_CONSTANTS)) {
            UserCoupon userCoupon = userCouponMapper.selectById(userItemOrderDetail.getUserCouponId());
            CouponConfig couponConfig = couponConfigMapper.selectById(userCoupon.getCouponId());
            userItemOrderDetail.setCouponDiscountPrice(couponConfig.getCouponSubtract());
        } else {
            userItemOrderDetail.setCouponDiscountPrice(BigDecimal.ZERO);
        }
        if (userItemOrderDetail.getOrderStatus().equals(OrderConstants.ORDER_STATUS_PENDING_PAYMENT)) {
            userItemOrderDetail.setCountdown((DateUtil.between(new Date(), DateUtil.offsetMinute(userItemOrderDetail.getPlaceOrderTime(), 10), DateUnit.SECOND, false)) <= 0 ? 0 : DateUtil.between(new Date(), DateUtil.offsetMinute(userItemOrderDetail.getPlaceOrderTime(), 10), DateUnit.SECOND, false));
        }
        List<UpgradeOrderDetail> upgradeOrderDetailList = new ArrayList<>();
        List<UserItemOrder> userItemOrders = userItemOrderMapper.selectList(new LambdaQueryWrapper<UserItemOrder>()
                .eq(UserItemOrder::getPartnerOrderNo, orderNo)
                .eq(UserItemOrder::getUserId, userId)
                .eq(UserItemOrder::getOrderType, NumberConstants.TWO_CONSTANTS)
                .notIn(UserItemOrder::getOrderStatus, OrderConstants.ORDER_STATUS_OVER, OrderConstants.ORDER_STATUS_CANCELLED));
        if (!CheckEmptyUtil.isEmpty(userItemOrders)) {
            userItemOrders.forEach(item -> {
                UpgradeOrderDetail vo = new UpgradeOrderDetail();
                vo.setOrderNo(item.getOrderNo());
                vo.setItemPicture(item.getItemPicture());
                vo.setOldItemName(userItemOrderDetail.getItemName());
                vo.setNewItemName(item.getItemName());
                vo.setOldItemPrice(userItemOrderDetail.getItemPrice());
                vo.setNewItemPrice(item.getOrderItemPrice());
                vo.setItemTime(item.getItemTime());
                vo.setOrderNum(item.getOrderNum());
                vo.setDifferentPrice(item.getNeedPayPrice());
                vo.setPlaceOrderTime(item.getPlaceOrderTime());
                vo.setPayTime(item.getPayTime());
                vo.setPayType(item.getPayType());
                vo.setOrderStatus(item.getOrderStatus());
                upgradeOrderDetailList.add(vo);
            });
        }

        int upgradeCount = userItemOrderMapper.selectCount(new LambdaQueryWrapper<UserItemOrder>()
                .in(UserItemOrder::getPartnerOrderNo, orderNo)
                .eq(UserItemOrder::getUserId, userId)
                .eq(UserItemOrder::getOrderType, NumberConstants.TWO_CONSTANTS)
                .eq(UserItemOrder::getOrderStatus, OrderConstants.ORDER_STATUS_UPGRADES_NOT_PAID)).intValue();
        if (upgradeCount > 0) {
            userItemOrderDetail.setOrderStatus(OrderConstants.ORDER_STATUS_UPGRADES_NOT_PAID);
        }
        userItemOrderDetail.setUpgradeOrderDetailList(upgradeOrderDetailList);

        List<BellOrderDetail> bellOrderDetailList = new ArrayList<>();
        List<UserItemOrder> userItemOrders1 = userItemOrderMapper.selectList(new LambdaQueryWrapper<UserItemOrder>()
                .eq(UserItemOrder::getPartnerOrderNo, orderNo)
                .eq(UserItemOrder::getUserId, userId)
                .eq(UserItemOrder::getOrderType, NumberConstants.ONE_CONSTANTS)
                .notIn(UserItemOrder::getOrderStatus, OrderConstants.ORDER_STATUS_OVER, OrderConstants.ORDER_STATUS_CANCELLED));
        if (!CheckEmptyUtil.isEmpty(userItemOrders1)) {
            userItemOrders1.forEach(item -> {
                BellOrderDetail vo = new BellOrderDetail();
                vo.setOrderNo(item.getOrderNo());
                vo.setItemPicture(item.getItemPicture());
                vo.setItemName(item.getItemName());
                vo.setItemPrice(item.getOrderItemPrice());
                vo.setItemTime(item.getItemTime());
                vo.setOrderNum(item.getOrderNum());
                vo.setPlaceOrderTime(item.getPlaceOrderTime());
                vo.setPayTime(item.getPayTime());
                vo.setPayType(item.getPayType());
                vo.setOrderStatus(item.getOrderStatus());
                bellOrderDetailList.add(vo);
            });
        }


        // 批量查询铃铛订单
        int bellOrderCount = userItemOrderMapper.selectCount(new LambdaQueryWrapper<UserItemOrder>()
                .in(UserItemOrder::getPartnerOrderNo, orderNo)
                .eq(UserItemOrder::getUserId, userId)
                .eq(UserItemOrder::getOrderType, NumberConstants.ONE_CONSTANTS)
                .eq(UserItemOrder::getOrderStatus, OrderConstants.ORDER_STATUS_BELL_NOT_PAID)).intValue();
        if (bellOrderCount > 0) {
            userItemOrderDetail.setOrderStatus(OrderConstants.ORDER_STATUS_BELL_NOT_PAID);
        }
        userItemOrderDetail.setBellOrderDetailList(bellOrderDetailList);

        return ApiRestResponse.success(userItemOrderDetail);
    }


    @Override
    public ApiRestResponse<CreateOrderResponseVo> replaceTechnicianCreateOrderDetail(Long userId, CreateOrderVo createOrderVo) throws ParseException {
        //UserItemOrder userItemOrder = userItemOrderMapper.selectOne(new LambdaQueryWrapper<UserItemOrder>()
        //        .eq(UserItemOrder::getOrderNo, createOrderVo.getOrderNo()));
        UserItemOrder userItemOrder = userItemOrderMapper.selectOneByOrderNo(createOrderVo.getOrderNo());

        if (CheckEmptyUtil.isEmpty(userItemOrder)) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.ORDER_EMPTY);
        }
        if (!userItemOrder.getOrderStatus().equals(OrderConstants.ORDER_STATUS_PENDING_ACCEPTANCE) &&
                !userItemOrder.getOrderStatus().equals(OrderConstants.ORDER_STATUS_PENDING_DEPARTURE) &&
                !userItemOrder.getOrderStatus().equals(OrderConstants.ORDER_STATUS_PENDING_START)) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.CANT_CANCEL_ORDER);
        }

        CreateOrderResponseVo responseVo = new CreateOrderResponseVo();
        UserAddress userAddress = userAddressMapper.selectById(createOrderVo.getAddressId());
        if (CheckEmptyUtil.isEmpty(userAddress)) {
            responseVo.setAddressName(userItemOrder.getAddressUserName());
            responseVo.setAddressTel(userItemOrder.getAddressTel());
            responseVo.setAddress(userItemOrder.getAddressDetail());
        } else {
            responseVo.setAddressName(userAddress.getAddressName());
            responseVo.setAddressTel(userAddress.getAddressTel());
            responseVo.setAddress(userAddress.getAddress() + userAddress.getAddressDetails());
        }
        responseVo.setItemMainPicture(userItemOrder.getItemPicture());
        responseVo.setItemSpecsName(userItemOrder.getItemName());
        responseVo.setItemSpecsPrice(userItemOrder.getOrderItemPrice());
        responseVo.setItemNum(userItemOrder.getOrderNum());
        Technician technician = technicianMapper.selectById(createOrderVo.getTid());
        if (userId.equals(technician.getUserId())) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.USER_TECHNICIAN_ONE);
        }
        BigDecimal carFee;
        responseVo.setTechnicianName(technician.getTechnicianName());
        responseVo.setTechnicianAvatar(technician.getTechnicianAvatar());
        TechnicianTime technicianTime = technicianTimeMapper.selectById(createOrderVo.getTechnicianTimeId());
        if (!CheckEmptyUtil.isEmpty(technicianTime)) {
            responseVo.setTechnicianTime(technicianTime.getDay() + " " + technicianTime.getTime());
            responseVo.setTechnicianTimeId(createOrderVo.getTechnicianTimeId());
        } else {
            SelectLatelyTime selectLatelyTime = technicianTimeMapper.selectLatelyTime(technician.getId(), DateUtil.today().substring(DateUtil.today().indexOf("-") + 1), 0);
            if (!CheckEmptyUtil.isEmpty(selectLatelyTime)) {
                responseVo.setTechnicianTime(selectLatelyTime.getDay() + " " + selectLatelyTime.getTime());
                responseVo.setTechnicianTimeId(selectLatelyTime.getId());
                createOrderVo.setTechnicianTimeId(selectLatelyTime.getId());
            } else {
                String torm = DateUtil.format(DateUtil.offsetDay(new Date(), 1), "yyyy-MM-dd");
                SelectLatelyTime selectTormLatelyTime = technicianTimeMapper.selectTormLatelyTime(technician.getId(), torm.substring(torm.indexOf("-") + 1));
                if (!CheckEmptyUtil.isEmpty(selectTormLatelyTime)) {
                    responseVo.setTechnicianTime(selectTormLatelyTime.getDay() + " " + selectTormLatelyTime.getTime());
                    responseVo.setTechnicianTimeId(selectTormLatelyTime.getId());
                    createOrderVo.setTechnicianTimeId(selectTormLatelyTime.getId());
                }
            }

        }
        if (!CheckEmptyUtil.isEmpty(createOrderVo.getTechnicianTimeId())) {
            CreateOrderResponseVo sumCarFare = sumCarFare(userItemOrder.getAddressId(), technician, createOrderVo.getTechnicianTimeId());
            responseVo.setDistance(sumCarFare.getDistance());
            responseVo.setCarFare(sumCarFare.getCarFare());
            responseVo.setDistance(sumCarFare.getDistance());
            carFee = sumCarFare.getCarFare();
        } else {
            responseVo.setTechnicianTime(userItemOrder.getServiceTime());
            responseVo.setCarFare(userItemOrder.getOrderFarePrice());
            responseVo.setDistance(userItemOrder.getDistance());
            carFee = userItemOrder.getOrderFarePrice();
        }

        //responseVo.setIsVip(userItemOrder.getIsOpenMembership());
        responseVo.setVipId(userItemOrder.getOpenMemberId());
        MemberConfig memberConfig = memberConfigMapper.selectById(userItemOrder.getOpenMemberId());
        if (!CheckEmptyUtil.isEmpty(memberConfig)) {
            responseVo.setVipName(memberConfig.getMemberName());
            responseVo.setVipPrice(memberConfig.getMemberPrice());
            responseVo.setVipDiscountPrice(memberConfig.getMemberDiscountPrice());
        }
        responseVo.setOpenVipPrice(userItemOrder.getOpenMemberPrice());
        int isVip = userMemberMapper.selectCount(new LambdaQueryWrapper<UserMember>()
                .eq(UserMember::getUserId, userId)).intValue();
        responseVo.setIsVip(isVip);
        CreateOrderResponseVo sumItem = sumItem(userItemOrder.getItemSpecsId(), userItemOrder.getOrderNum(), isVip, userItemOrder.getIsOpenMembership());
        responseVo.setItemPrice(sumItem.getItemPrice());
        responseVo.setItemVipPrice(sumItem.getItemVipPrice());
        responseVo.setItemDiscountPrice(sumItem.getItemDiscountPrice());

        if (userItemOrder.getIsUserCoupon().equals(NumberConstants.ONE_CONSTANTS)) {
            UserCoupon userCoupon = userCouponMapper.selectById(userItemOrder.getUserCouponId());
            CouponConfig couponConfig = couponConfigMapper.selectById(userCoupon.getCouponId());
            responseVo.setCouponName(couponConfig.getCouponName());
            responseVo.setCouponDiscountPrice(couponConfig.getCouponSubtract());
        } else {
            responseVo.setCouponDiscountPrice(BigDecimal.ZERO);
        }

        responseVo.setDiscountTotalPrice(userItemOrder.getDiscountPrice());
        if (userItemOrder.getOrderStatus().equals(OrderConstants.ORDER_STATUS_PENDING_ACCEPTANCE) || userItemOrder.getOrderStatus().equals(OrderConstants.ORDER_STATUS_PENDING_DEPARTURE)) {
            if (carFee.compareTo(userItemOrder.getOrderFarePrice()) > 0) {
                carFee = carFee.subtract(userItemOrder.getOrderFarePrice());
            } else {
                carFee = BigDecimal.ZERO;
            }

        }
        if (carFee.compareTo(new BigDecimal(0)) == 0) {
            carFee = new BigDecimal("0.01");
        }
        responseVo.setPayTotalPrice(carFee);


        return ApiRestResponse.success(responseVo);
    }

    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public ApiRestResponse replaceTechnicianCreateOrder(User user, CreateOrderVo createOrderVo) throws Exception {
        //将订单状态改为已取消
        //UserItemOrder userItemOrder = userItemOrderMapper.selectOne(new LambdaQueryWrapper<UserItemOrder>()
        //        .eq(UserItemOrder::getOrderNo, createOrderVo.getOrderNo()));
        UserItemOrder userItemOrder = userItemOrderMapper.selectOneByOrderNo(createOrderVo.getOrderNo());

        if (CheckEmptyUtil.isEmpty(userItemOrder)) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.ORDER_EMPTY);
        }
        if (!userItemOrder.getOrderStatus().equals(OrderConstants.ORDER_STATUS_PENDING_ACCEPTANCE) &&
                !userItemOrder.getOrderStatus().equals(OrderConstants.ORDER_STATUS_PENDING_DEPARTURE) &&
                !userItemOrder.getOrderStatus().equals(OrderConstants.ORDER_STATUS_PENDING_START)) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.CANT_CANCEL_ORDER);
        }
        BigDecimal oldCarFare;
        if (userItemOrder.getOrderStatus().equals(OrderConstants.ORDER_STATUS_PENDING_ACCEPTANCE)
                || userItemOrder.getOrderStatus().equals(OrderConstants.ORDER_STATUS_PENDING_DEPARTURE)) {
            oldCarFare = userItemOrder.getOrderFarePrice();

        } else {
            //需要将路费结算给技师
            oldCarFare = BigDecimal.ZERO;
            // TODO 将上个路费结算给上个技师
            TechnicianConsumeDetail technicianConsume = new TechnicianConsumeDetail();
            technicianConsume.setTid(createOrderVo.getTid());
            technicianConsume.setConsumeType(CommonConstants.CONSUMPTION_ADD);
            technicianConsume.setOrderNo(userItemOrder.getOrderNo());
            technicianConsume.setFareRevenue(userItemOrder.getOrderFarePrice());
            technicianConsume.setItemRevenue(userItemOrder.getOrderItemPrice());
            technicianConsume.setConsumptionDescribe("用户更换技师结余");
            technicianConsumeDetailMapper.insert(technicianConsume);
        }


        userItemOrder.setOrderStatus(OrderConstants.ORDER_STATUS_CANCELLED);
        userItemOrderMapper.updateById(userItemOrder);
        TechnicianItemOrder technicianItemOrder1 = technicianItemOrderMapper.selectOne(new LambdaQueryWrapper<TechnicianItemOrder>().eq(TechnicianItemOrder::getOrderNo, createOrderVo.getOrderNo()));
        if (CheckEmptyUtil.isEmpty(technicianItemOrder1)) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.ORDER_EMPTY);
        }
        technicianItemOrder1.setOrderStatus(OrderConstants.ORDER_STATUS_CANCELLED);

        technicianItemOrderMapper.updateById(technicianItemOrder1);

        //判断用户地址
        UserAddress address = userAddressMapper.selectById(createOrderVo.getAddressId());
        if (CheckEmptyUtil.isEmpty(address)) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.ADDRESS_ERROR);
        }
        //查询技师是否在线
        Technician technician = technicianMapper.selectById(createOrderVo.getTid());
        if (technician.getIsOnline().equals(NumberConstants.ZERO_CONSTANTS)) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.TECHNICIAN_NOT_ONLINE);
        }
        if (user.getId().equals(technician.getUserId())) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.USER_TECHNICIAN_ONE);
        }
        TechnicianTime technicianTime = technicianTimeMapper.selectById(createOrderVo.getTechnicianTimeId());
        if (CheckEmptyUtil.isEmpty(technicianTime)) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.SERVICE_TIME_EMPTY);
        }
        ItemSpecs itemSpecs = itemSpecsMapper.selectById(createOrderVo.getItemSpecsId());
        Item item = !CheckEmptyUtil.isEmpty(itemSpecs) ? itemMapper.selectById(itemSpecs.getItemId()) : itemMapper.selectById(createOrderVo.getItemSpecsId());


        //只能选择当前时间一小时之后的时间
        parseStringToDate(technicianTime.getDay(), technicianTime.getTime());
        //先查询该时间技师是否有正在进行中的的订单
        // 如果没有正常下单
        // 如果有 算出正常完成项目后的时间  与用户选择的时间进行比较 如果订单完成时间小于用户选择的时间 则为不可选
        TechnicianItemOrder technicianItemOrder = technicianItemOrderMapper.selectOneTakingOrder(createOrderVo.getTid());
        if (!CheckEmptyUtil.isEmpty(technicianItemOrder)) {
            String serviceTime = technicianItemOrder.getServiceTime();
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
            //服务完成时间
            DateTime itemFinshTime = sumOrderFinishTime(simpleDateFormat, serviceTime, technicianItemOrder.getItemTime() * technicianItemOrder.getOrderNum());
            //选择时间
            String choseTime1 = DateUtil.thisYear() + "-" + technicianTime.getDay() + " " + technicianTime.getTime();
            Date choseTime = simpleDateFormat.parse(choseTime1);
            if (itemFinshTime.isAfter(choseTime)) {
                throw new ErrorCodeException(ErrorCodeExceptionEnum.SERVICE_TIME_NOT_USE);
            }
        }

        //计算费用
        CreateOrderResponseVo data = createOrderDetail(user.getId(), createOrderVo).getData();
        //项目费
        BigDecimal itemTotalPrice = data.getItemSpecsPrice();
        //开通会员金额
        BigDecimal openVipPrice = data.getOpenVipPrice();
        //共优惠金额
        BigDecimal discountTotalPrice = data.getDiscountTotalPrice();
        //车费
        BigDecimal carFare = data.getCarFare();
        //支付金额
        BigDecimal payTotalPrice = data.getPayTotalPrice();
        BigDecimal distance = data.getDistance();
        //如果 原路费 > 现在的路费
        //需要退还多余的路费给用户
        if (oldCarFare.compareTo(carFare) > 0) {
            //并退还多余路费给用户
            BigDecimal returnPrice = oldCarFare.subtract(carFare).add(new BigDecimal("0.01"));
            Integer i = userMapper.addBalance(user.getId(), returnPrice);
            if (i > 0) {
                UserConsumeDetail userConsumeDetail = new UserConsumeDetail();
                userConsumeDetail.setUserId(user.getId());
                userConsumeDetail.setConsumptionDescribe("更换技师多余路费退还");
                userConsumeDetail.setOrderNo(userItemOrder.getOrderNo());
                userConsumeDetail.setConsumptionPrice(returnPrice);
                userConsumeDetail.setConsumptionType(CommonConstants.CONSUMPTION_ADD);
                userConsumeDetailMapper.insert(userConsumeDetail);
            }
            //carFare = BigDecimal.ZERO;
            carFare = new BigDecimal("0.01");
        } else {
            carFare = carFare.subtract(oldCarFare);
        }

        if (carFare.compareTo(BigDecimal.ZERO) == 0) {
            carFare = new BigDecimal("0.01");
        }


        String orderNo = RandomUtils.getOrderNo();
        UserItemOrder insertUserItemOrder = new UserItemOrder();
        insertUserItemOrder.setOrderNo(orderNo);
        insertUserItemOrder.setUserId(user.getId());
        insertUserItemOrder.setTid(createOrderVo.getTid());
        insertUserItemOrder.setItemId(item.getId());
        insertUserItemOrder.setItemSpecsId(createOrderVo.getItemSpecsId());
        insertUserItemOrder.setItemName(!CheckEmptyUtil.isEmpty(itemSpecs) ? itemSpecs.getItemSpecsName() : item.getItemName());
        insertUserItemOrder.setItemPicture(item.getItemMainPicture());
        insertUserItemOrder.setItemTime(!CheckEmptyUtil.isEmpty(itemSpecs) ? itemSpecs.getItemSpecsTime() * createOrderVo.getItemNum() : item.getItemTime() * createOrderVo.getItemNum());
        insertUserItemOrder.setAddressId(address.getId());
        insertUserItemOrder.setAddressUserName(address.getAddressName());
        insertUserItemOrder.setAddressTel(address.getAddressTel());
        insertUserItemOrder.setAddressDetail(address.getAddress() + address.getAddressDetails());
        insertUserItemOrder.setServiceTime(technicianTime.getYear() + "-" + technicianTime.getDay() + " " + technicianTime.getTime());
        insertUserItemOrder.setNeedPayPrice(carFare);
        insertUserItemOrder.setOrderTotalPrice(payTotalPrice);
        insertUserItemOrder.setOrderItemPrice(itemTotalPrice);
        insertUserItemOrder.setOrderFarePrice(carFare);
        insertUserItemOrder.setDiscountPrice(discountTotalPrice);
        insertUserItemOrder.setIsUserCoupon(createOrderVo.getIsUserCoupon());
        insertUserItemOrder.setUserCouponId(createOrderVo.getUserCouponId());
        insertUserItemOrder.setUserCouponPrice(sumCoupon(createOrderVo.getIsUserCoupon(), createOrderVo.getUserCouponId()).getCouponDiscountPrice());

        insertUserItemOrder.setPlaceOrderTime(new Date());
        insertUserItemOrder.setOrderNum(createOrderVo.getItemNum());
        insertUserItemOrder.setIsOpenMembership(createOrderVo.getIsOpenVip());
        insertUserItemOrder.setOpenMemberId(createOrderVo.getVipId());
        insertUserItemOrder.setOpenMemberPrice(openVipPrice);
        insertUserItemOrder.setDistance(distance);
        insertUserItemOrder.setModeTravel(createOrderVo.getModeTravel());
        insertUserItemOrder.setOrderRemark(createOrderVo.getOrderRemark());
        insertUserItemOrder.setOrderStatus(OrderConstants.ORDER_STATUS_PENDING_PAYMENT);
        userItemOrderMapper.insert(insertUserItemOrder);


        TechnicianItemOrder insertTechnicianItemOrder = new TechnicianItemOrder();
        insertTechnicianItemOrder.setOrderNo(orderNo);
        insertTechnicianItemOrder.setUserId(user.getId());
        insertTechnicianItemOrder.setTid(createOrderVo.getTid());
        insertTechnicianItemOrder.setItemId(item.getId());
        insertTechnicianItemOrder.setItemSpecsId(createOrderVo.getItemSpecsId());
        insertTechnicianItemOrder.setItemName(!CheckEmptyUtil.isEmpty(itemSpecs) ? itemSpecs.getItemSpecsName() : item.getItemName());
        insertTechnicianItemOrder.setItemPicture(item.getItemMainPicture());
        insertTechnicianItemOrder.setItemTime(!CheckEmptyUtil.isEmpty(itemSpecs) ? itemSpecs.getItemSpecsTime() * createOrderVo.getItemNum() : item.getItemTime() * createOrderVo.getItemNum());
        insertTechnicianItemOrder.setAddressId(address.getId());
        insertTechnicianItemOrder.setAddressUserName(address.getAddressName());
        insertTechnicianItemOrder.setAddressTel(address.getAddressTel());
        insertTechnicianItemOrder.setAddressDetail(address.getAddress() + address.getAddressDetails());
        insertTechnicianItemOrder.setServiceTime(technicianTime.getYear() + "-" + technicianTime.getDay() + " " + technicianTime.getTime());
        insertTechnicianItemOrder.setNeedPayPrice(carFare);
        insertTechnicianItemOrder.setOrderTotalPrice(payTotalPrice);
        insertTechnicianItemOrder.setOrderItemPrice(itemTotalPrice);
        insertTechnicianItemOrder.setOrderFarePrice(carFare);
        insertTechnicianItemOrder.setDiscountPrice(discountTotalPrice);
        insertTechnicianItemOrder.setIsUserCoupon(createOrderVo.getIsUserCoupon());
        insertTechnicianItemOrder.setUserCouponId(createOrderVo.getUserCouponId());
        insertTechnicianItemOrder.setUserCouponPrice(sumCoupon(createOrderVo.getIsUserCoupon(), createOrderVo.getUserCouponId()).getCouponDiscountPrice());

        insertTechnicianItemOrder.setPlaceOrderTime(new Date());
        insertTechnicianItemOrder.setOrderNum(createOrderVo.getItemNum());
        insertTechnicianItemOrder.setIsOpenMembership(createOrderVo.getIsOpenVip());
        insertTechnicianItemOrder.setOpenMemberId(createOrderVo.getVipId());
        insertTechnicianItemOrder.setOpenMemberPrice(openVipPrice);
        insertTechnicianItemOrder.setDistance(distance);
        insertTechnicianItemOrder.setOrderRemark(createOrderVo.getOrderRemark());
        insertTechnicianItemOrder.setModeTravel(createOrderVo.getModeTravel());
        insertTechnicianItemOrder.setOrderStatus(OrderConstants.ORDER_STATUS_PENDING_PAYMENT);
        technicianItemOrderMapper.insert(insertTechnicianItemOrder);


        Message message = new Message();
        message.setUserId(user.getId());
        message.setOrderNo(orderNo);
        message.setMessageTitle("您有一条待支付订单");
        message.setMessageComment("您有一条待支付订单");
        messageMapper.insert(message);
        PayOrderRequestVo request = new PayOrderRequestVo();
        request.setUser(user);
        request.setOrderNo(orderNo);
        request.setPayType(createOrderVo.getPayType());
        request.setWxType(createOrderVo.getWxType());
        request.setReturnUrl(createOrderVo.getReturnUrl());
        request.setQuitUrl(createOrderVo.getQuitUrl());
        return payOrder(request);
    }

    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public ApiRestResponse<Integer> confirmOrder(Long userId, ConfirmOrderVo confirmOrderVo) throws Exception {
        //UserItemOrder userItemOrder = userItemOrderMapper.selectOne(new LambdaQueryWrapper<UserItemOrder>()
        //        .eq(UserItemOrder::getOrderNo, confirmOrderVo.getOrderNo()));
        UserItemOrder userItemOrder = userItemOrderMapper.selectOneByOrderNo(confirmOrderVo.getOrderNo());

        if (CheckEmptyUtil.isEmpty(userItemOrder)) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.ORDER_EMPTY);
        }
        if (!userItemOrder.getOrderStatus().equals(OrderConstants.ORDER_STATUS_PENDING_CONFIRMED_PAYMENT)) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.CANT_CANCEL_CONFIRMED);
        }
        Integer update = userConfirmOrder(userItemOrder);
        //更新技师已售单量
        return ApiRestResponse.success(update);
    }

    @Override
    public Integer userConfirmOrder(UserItemOrder userItemOrder) throws Exception {
        userItemOrder.setOrderStatus(OrderConstants.ORDER_STATUS_PENDING_EVALUATION);
        userItemOrderMapper.updateById(userItemOrder);
        //更改下级订单状态
        userItemOrderMapper.updateOrderStatus(userItemOrder.getOrderNo(), OrderConstants.ORDER_STATUS_PENDING_EVALUATION);
        //将技师资金状态解冻
        TechnicianConsumeDetail technicianConsumeDetail = technicianConsumeDetailMapper.selectOne(new LambdaQueryWrapper<TechnicianConsumeDetail>()
                .eq(TechnicianConsumeDetail::getOrderNo, userItemOrder.getOrderNo()));
        technicianConsumeDetail.setPriceStatus(NumberConstants.ONE_CONSTANTS);
        technicianConsumeDetailMapper.updateById(technicianConsumeDetail);
        Technician technician = technicianMapper.selectById(userItemOrder.getTid());


        technicianItemOrderMapper.updateOrderStatus(userItemOrder.getOrderNo(), OrderConstants.ORDER_STATUS_PENDING_EVALUATION);
        TechnicianItemOrder technicianItemOrder = technicianItemOrderMapper.selectOne(new LambdaQueryWrapper<TechnicianItemOrder>()
                .eq(TechnicianItemOrder::getOrderNo, userItemOrder.getOrderNo()));

        technicianItemOrder.setOrderStatus(OrderConstants.ORDER_STATUS_PENDING_EVALUATION);
        int update = technicianItemOrderMapper.updateById(technicianItemOrder);

        // 修改技师等级
        technicianConsumeDetailService.updateTechnicianConsumeGrade(technician);

        // 给推荐人收益
        giveReward(userItemOrder, technician);


        return update;
    }


    private void giveReward(UserItemOrder userItemOrder, Technician technician) {
        User user = userMapper.selectById(userItemOrder.getUserId());
        //查该用户的上级
        User partnerUser = userMapper.selectOne(new LambdaQueryWrapper<User>()
                .eq(User::getUserInvitationCode, user.getUserInvitedCode()));

        //查询技师的上级
        Technician partnerTechnician = technicianMapper.selectOne(new LambdaQueryWrapper<Technician>()
                .eq(Technician::getTechnicianInvitationCode, technician.getTechnicianInvitedCode()));
        //升级套餐收益
        processUpgradeOrder(userItemOrder, user, partnerUser, technician, partnerTechnician);
        //加钟订单收益
        processBellOrder(userItemOrder, user, partnerUser, technician, partnerTechnician);
    }


    private void processUpgradeOrder(UserItemOrder userItemOrder, User user, User partnerUser, Technician technician, Technician partnerTechnician) {
        //查该项目是否有升级套餐
        List<UserItemOrder> upgradeOrders = userItemOrderMapper.selectList(new LambdaQueryWrapper<UserItemOrder>()
                .eq(UserItemOrder::getPartnerOrderNo, userItemOrder.getOrderNo())
                .eq(UserItemOrder::getOrderType, NumberConstants.TWO_CONSTANTS)
        );
        if (!CheckEmptyUtil.isEmpty(upgradeOrders)) {
            if (!CheckEmptyUtil.isEmpty(partnerTechnician)) {
                if (partnerTechnician.getTechnicianIdentity().equals(NumberConstants.ONE_CONSTANTS)) {
                    //经纪人
                    Broker broker = brokerMapper.selectOne(new LambdaQueryWrapper<Broker>().eq(Broker::getTid, partnerTechnician.getId()));
                    BigDecimal brokerUpgradeRate = getBrokerRate(broker, NumberConstants.ONE_CONSTANTS);
                    upgradeOrders.forEach(item -> {
                        setBrokerConsumeDetail(item.getOrderNo(), broker.getId(), user.getUserNikeName(), technician.getTechnicianName(), item.getOrderNum(),
                                item.getItemName(), item.getItemPicture(), item.getPayTime(), item.getOrderTotalPrice(), item.getOrderItemPrice(), brokerUpgradeRate);
                    });
                }
            }
            if (!CheckEmptyUtil.isEmpty(partnerUser)) {
                if (partnerUser.getUserIdentity().equals(NumberConstants.ONE_CONSTANTS)) {
                    //业务员
                    Salesman salesman = salesmanMapper.selectOne(new LambdaQueryWrapper<Salesman>().eq(Salesman::getUserId, partnerUser.getId()));
                    BigDecimal salesmanUpgradeRate = getSalesmanRate(salesman, NumberConstants.ONE_CONSTANTS);
                    upgradeOrders.forEach(item -> {
                        setSalesmanConsumeDetail(item.getOrderNo(), salesman.getId(), user.getUserNikeName(), technician.getTechnicianName(), item.getOrderNum(),
                                item.getItemName(), item.getItemPicture(), item.getPayTime(), item.getOrderTotalPrice(), item.getOrderItemPrice(), salesmanUpgradeRate);
                    });
                } else if (partnerUser.getUserIdentity().equals(NumberConstants.TWO_CONSTANTS)) {
                    //渠道商
                    ChannelMerchants channelMerchants = channelMerchantsMapper.selectOne(new LambdaQueryWrapper<ChannelMerchants>().eq(ChannelMerchants::getUserId, partnerUser.getId()));
                    BigDecimal channelUpgradeRate = getChannelRate(channelMerchants, NumberConstants.ONE_CONSTANTS);
                    upgradeOrders.forEach(item -> {
                        setChannelConsumeDetail(item.getOrderNo(), channelMerchants.getId(), user.getUserNikeName(), technician.getTechnicianName(), item.getOrderNum(),
                                item.getItemName(), item.getItemPicture(), item.getPayTime(), item.getOrderTotalPrice(), item.getOrderItemPrice(), channelUpgradeRate);
                    });
                }
            }
        } else {
            //原项目
            if (!CheckEmptyUtil.isEmpty(partnerTechnician)) {
                if (partnerTechnician.getTechnicianIdentity().equals(NumberConstants.ONE_CONSTANTS)) {
                    //经纪人
                    Broker broker = brokerMapper.selectOne(new LambdaQueryWrapper<Broker>().eq(Broker::getTid, partnerTechnician.getId()));
                    BigDecimal brokerRate = getBrokerRate(broker, NumberConstants.ZERO_CONSTANTS);
                    setBrokerConsumeDetail(userItemOrder.getOrderNo(), broker.getId(), user.getUserNikeName(), technician.getTechnicianName(), userItemOrder.getOrderNum(),
                            userItemOrder.getItemName(), userItemOrder.getItemPicture(), userItemOrder.getPayTime(), userItemOrder.getOrderTotalPrice(), userItemOrder.getOrderItemPrice(), brokerRate);
                }
            }
            if (!CheckEmptyUtil.isEmpty(partnerUser)) {
                if (partnerUser.getUserIdentity().equals(NumberConstants.ONE_CONSTANTS)) {
                    //业务员
                    Salesman salesman = salesmanMapper.selectOne(new LambdaQueryWrapper<Salesman>().eq(Salesman::getUserId, partnerUser.getId()));
                    BigDecimal salesmanRate = getSalesmanRate(salesman, NumberConstants.ZERO_CONSTANTS);
                    setSalesmanConsumeDetail(userItemOrder.getOrderNo(), salesman.getId(), user.getUserNikeName(), technician.getTechnicianName(), userItemOrder.getOrderNum(),
                            userItemOrder.getItemName(), userItemOrder.getItemPicture(), userItemOrder.getPayTime(), userItemOrder.getOrderTotalPrice(), userItemOrder.getOrderItemPrice(), salesmanRate);

                } else if (partnerUser.getUserIdentity().equals(NumberConstants.TWO_CONSTANTS)) {
                    //渠道商
                    ChannelMerchants channelMerchants = channelMerchantsMapper.selectOne(new LambdaQueryWrapper<ChannelMerchants>().eq(ChannelMerchants::getUserId, partnerUser.getId()));
                    BigDecimal channelRate = getChannelRate(channelMerchants, NumberConstants.ZERO_CONSTANTS);
                    setChannelConsumeDetail(userItemOrder.getOrderNo(), channelMerchants.getId(), user.getUserNikeName(), technician.getTechnicianName(), userItemOrder.getOrderNum(),
                            userItemOrder.getItemName(), userItemOrder.getItemPicture(), userItemOrder.getPayTime(), userItemOrder.getOrderTotalPrice(), userItemOrder.getOrderItemPrice(), channelRate);


                }
            }
        }

    }

    private void processBellOrder(UserItemOrder userItemOrder, User user, User partnerUser, Technician technician, Technician partnerTechnician) {
        //加钟项目
        List<UserItemOrder> bellOrders = userItemOrderMapper.selectList(new LambdaQueryWrapper<UserItemOrder>()
                .eq(UserItemOrder::getPartnerOrderNo, userItemOrder.getOrderNo())
                .eq(UserItemOrder::getOrderType, NumberConstants.ONE_CONSTANTS));
        if (!CheckEmptyUtil.isEmpty(bellOrders)) {
            //第一条加钟订单
            UserItemOrder firstOrder = bellOrders.get(0);
            if (!CheckEmptyUtil.isEmpty(partnerTechnician)) {
                if (partnerTechnician.getTechnicianIdentity().equals(NumberConstants.ONE_CONSTANTS)) {
                    //经纪人
                    Broker broker = brokerMapper.selectOne(new LambdaQueryWrapper<Broker>().eq(Broker::getTid, partnerTechnician.getId()));
                    BigDecimal brokerFirstBellRate = getBrokerRate(broker, NumberConstants.TWO_CONSTANTS);
                    setBrokerConsumeDetail(firstOrder.getOrderNo(), broker.getId(), user.getUserNikeName(), technician.getTechnicianName(), firstOrder.getOrderNum(),
                            firstOrder.getItemName(), firstOrder.getItemPicture(), firstOrder.getPayTime(), firstOrder.getOrderTotalPrice(), firstOrder.getOrderItemPrice(), brokerFirstBellRate);
                }
            }
            if (!CheckEmptyUtil.isEmpty(partnerUser)) {
                if (partnerUser.getUserIdentity().equals(NumberConstants.ONE_CONSTANTS)) {
                    //业务员
                    Salesman salesman = salesmanMapper.selectOne(new LambdaQueryWrapper<Salesman>().eq(Salesman::getUserId, partnerUser.getId()));
                    BigDecimal salesmanFristBellRate = getSalesmanRate(salesman, NumberConstants.TWO_CONSTANTS);
                    setSalesmanConsumeDetail(userItemOrder.getOrderNo(), salesman.getId(), user.getUserNikeName(), technician.getTechnicianName(), userItemOrder.getOrderNum(),
                            userItemOrder.getItemName(), userItemOrder.getItemPicture(), userItemOrder.getPayTime(), userItemOrder.getOrderTotalPrice(), userItemOrder.getOrderItemPrice(), salesmanFristBellRate);

                } else if (partnerUser.getUserIdentity().equals(NumberConstants.TWO_CONSTANTS)) {
                    //渠道商
                    ChannelMerchants channelMerchants = channelMerchantsMapper.selectOne(new LambdaQueryWrapper<ChannelMerchants>().eq(ChannelMerchants::getUserId, partnerUser.getId()));
                    BigDecimal channelFirstBellRate = getChannelRate(channelMerchants, NumberConstants.TWO_CONSTANTS);

                    setChannelConsumeDetail(firstOrder.getOrderNo(), channelMerchants.getId(), user.getUserNikeName(), technician.getTechnicianName(), firstOrder.getOrderNum(),
                            firstOrder.getItemName(), firstOrder.getItemPicture(), firstOrder.getPayTime(), firstOrder.getOrderTotalPrice(), firstOrder.getOrderItemPrice(), channelFirstBellRate);

                }
            }
            //多条加钟数据
            if (bellOrders.size() > 1) {
                //除第一条加钟订单之外的加钟订单
                List<UserItemOrder> secondBellOrders = bellOrders.stream().skip(1).collect(Collectors.toList());
                if (!CheckEmptyUtil.isEmpty(secondBellOrders)) {
                    if (!CheckEmptyUtil.isEmpty(partnerTechnician)) {
                        if (partnerTechnician.getTechnicianIdentity().equals(NumberConstants.ONE_CONSTANTS)) {
                            //经纪人
                            Broker broker = brokerMapper.selectOne(new LambdaQueryWrapper<Broker>().eq(Broker::getTid, partnerTechnician.getId()));
                            BigDecimal brokerSecondBellRate = getBrokerRate(broker, NumberConstants.THREE_CONSTANTS);
                            secondBellOrders.forEach(item -> {
                                setBrokerConsumeDetail(item.getOrderNo(), broker.getId(), user.getUserNikeName(), technician.getTechnicianName(), item.getOrderNum(),
                                        item.getItemName(), item.getItemPicture(), item.getPayTime(), item.getOrderTotalPrice(), item.getOrderItemPrice(), brokerSecondBellRate);
                            });
                        }
                    }
                    if (!CheckEmptyUtil.isEmpty(partnerUser)) {
                        if (partnerUser.getUserIdentity().equals(NumberConstants.ONE_CONSTANTS)) {
                            //业务员
                            Salesman salesman = salesmanMapper.selectOne(new LambdaQueryWrapper<Salesman>().eq(Salesman::getUserId, partnerUser.getId()));
                            BigDecimal salesmanSecondBellRate = getSalesmanRate(salesman, NumberConstants.THREE_CONSTANTS);
                            secondBellOrders.forEach(item -> {
                                setSalesmanConsumeDetail(item.getOrderNo(), salesman.getId(), user.getUserNikeName(), technician.getTechnicianName(), item.getOrderNum(),
                                        item.getItemName(), item.getItemPicture(), item.getPayTime(), item.getOrderTotalPrice(), item.getOrderItemPrice(), salesmanSecondBellRate);
                            });

                        } else if (partnerUser.getUserIdentity().equals(NumberConstants.TWO_CONSTANTS)) {
                            //渠道商
                            ChannelMerchants channelMerchants = channelMerchantsMapper.selectOne(new LambdaQueryWrapper<ChannelMerchants>().eq(ChannelMerchants::getUserId, partnerUser.getId()));
                            BigDecimal channelSecondBellRate = getChannelRate(channelMerchants, NumberConstants.THREE_CONSTANTS);
                            secondBellOrders.forEach(item -> {
                                setChannelConsumeDetail(item.getOrderNo(), channelMerchants.getId(), user.getUserNikeName(), technician.getTechnicianName(), item.getOrderNum(),
                                        item.getItemName(), item.getItemPicture(), item.getPayTime(), item.getOrderTotalPrice(), item.getOrderItemPrice(), channelSecondBellRate);
                            });
                        }
                    }
                }
            }
        }
    }


    private void setSalesmanConsumeDetail(String orderNo, Long salesmanId, String userName, String technicianName, Integer orderNum, String itemName, String itemPicture,
                                          Date payTime, BigDecimal orderTotalPrice, BigDecimal orderTotalItemPrice, BigDecimal rate) {
        SalesmanConsumeDetail salesmanConsumeDetail = new SalesmanConsumeDetail();
        salesmanConsumeDetail.setOrderNo(orderNo);
        salesmanConsumeDetail.setSalesmanId(salesmanId);
        salesmanConsumeDetail.setPayUser(userName);
        salesmanConsumeDetail.setPayTechnicianName(technicianName);
        salesmanConsumeDetail.setPayCount(orderNum);
        salesmanConsumeDetail.setPayItemName(itemName);
        salesmanConsumeDetail.setPayItemPicture(itemPicture);
        salesmanConsumeDetail.setPayTime(payTime);
        salesmanConsumeDetail.setPayPrice(orderTotalPrice);
        salesmanConsumeDetail.setItemPrice(orderTotalItemPrice);
        salesmanConsumeDetail.setSharePrice(orderTotalItemPrice.multiply(rate));
        salesmanConsumeDetail.setConsumptionType(CommonConstants.CONSUMPTION_ADD);
        salesmanConsumeDetail.setConsumptionDescribe("订单" + orderNo + "收入");
        salesmanConsumeDetailMapper.insert(salesmanConsumeDetail);
    }

    private void setChannelConsumeDetail(String orderNo, Long channelId, String userName, String technicianName, Integer orderNum, String itemName, String itemPicture,
                                         Date payTime, BigDecimal orderTotalPrice, BigDecimal orderTotalItemPrice, BigDecimal rate) {
        ChannelConsumeDetail channelConsumeDetail = new ChannelConsumeDetail();
        channelConsumeDetail.setOrderNo(orderNo);
        channelConsumeDetail.setChannelId(channelId);
        channelConsumeDetail.setPayUser(userName);
        channelConsumeDetail.setPayTechnicianName(technicianName);
        channelConsumeDetail.setPayCount(orderNum);
        channelConsumeDetail.setPayItemName(itemName);
        channelConsumeDetail.setPayItemPicture(itemPicture);
        channelConsumeDetail.setPayTime(payTime);
        channelConsumeDetail.setPayPrice(orderTotalPrice);
        channelConsumeDetail.setItemPrice(orderTotalItemPrice);
        channelConsumeDetail.setSharePrice(orderTotalItemPrice.multiply(rate));
        channelConsumeDetail.setConsumptionType(CommonConstants.CONSUMPTION_ADD);
        channelConsumeDetail.setConsumptionDescribe("订单" + orderNo + "收入");
        channelConsumeDetailMapper.insert(channelConsumeDetail);
    }


    private void setBrokerConsumeDetail(String orderNo, Long brokerId, String userName, String technicianName, Integer orderNum, String itemName, String itemPicture,
                                        Date payTime, BigDecimal orderTotalPrice, BigDecimal orderTotalItemPrice, BigDecimal rate) {
        BrokerConsumeDetail brokerConsumeDetail = new BrokerConsumeDetail();
        brokerConsumeDetail.setOrderNo(orderNo);
        brokerConsumeDetail.setBrokerId(brokerId);
        brokerConsumeDetail.setPayUser(userName);
        brokerConsumeDetail.setPayTechnicianName(technicianName);
        brokerConsumeDetail.setPayCount(orderNum);
        brokerConsumeDetail.setPayItemName(itemName);
        brokerConsumeDetail.setPayItemPicture(itemPicture);
        brokerConsumeDetail.setPayTime(payTime);
        brokerConsumeDetail.setPayPrice(orderTotalPrice);
        brokerConsumeDetail.setItemPrice(orderTotalItemPrice);
        brokerConsumeDetail.setConsumptionPrice(orderTotalItemPrice.multiply(rate));
        brokerConsumeDetail.setConsumptionType(CommonConstants.CONSUMPTION_ADD);
        brokerConsumeDetail.setConsumptionDescribe("订单" + orderNo + "收入");
        brokerConsumeDetailMapper.insert(brokerConsumeDetail);
    }

    /**
     * 计算业务员分成比例
     *
     * @param salesman
     * @param type     0=正常项目 1=升级套餐 2=第一次加钟 3=第二次加钟
     * @return 分成比例（0.3）
     * @Date 2025 3月 31 13:58
     */
    private BigDecimal getSalesmanRate(Salesman salesman, Integer type) {
        BigDecimal salesmanRate;
        switch (type) {
            case 0:
                salesmanRate = salesman.getSplitRate().compareTo(BigDecimal.ZERO) == 0 ?
                        new BigDecimal(shareConfigMapper.getSalesmanSplitRate()).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP) :
                        salesman.getSplitRate().divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
                break;
            case 1:
                salesmanRate = salesman.getUpgradeSplitRate().compareTo(BigDecimal.ZERO) == 0 ?
                        new BigDecimal(shareConfigMapper.getSalesmanUpgradeSplitRate()).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP) :
                        salesman.getUpgradeSplitRate().divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
                break;
            case 2:
                salesmanRate = salesman.getBellFirstSplitRate().compareTo(BigDecimal.ZERO) == 0 ?
                        new BigDecimal(shareConfigMapper.getSalesmanFirstBlockSplitRate()).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP) :
                        salesman.getBellFirstSplitRate().divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
                break;
            case 3:
                salesmanRate = salesman.getBellSecondSplitRate().compareTo(BigDecimal.ZERO) == 0 ?
                        new BigDecimal(shareConfigMapper.getSalesmanSecondBlockSplitRate()).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP) :
                        salesman.getBellSecondSplitRate().divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
                break;
            default:
                salesmanRate = BigDecimal.ZERO;
                break;
        }
        return salesmanRate;
    }

    /**
     * 计算渠道商分成比例
     *
     * @param channelMerchants
     * @param type             0=正常项目 1=升级套餐 2=第一次加钟 3=第二次加钟
     * @return 分成比例（0.3）
     * @Date 2025 3月 31 14:10
     */
    private BigDecimal getChannelRate(ChannelMerchants channelMerchants, Integer type) {
        BigDecimal channelRate;
        switch (type) {
            case 0:
                channelRate = channelMerchants.getSplitRate().compareTo(BigDecimal.ZERO) == 0 ?
                        new BigDecimal(shareConfigMapper.getChannelSplitRate()).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP) :
                        channelMerchants.getSplitRate().divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
                break;
            case 1:
                channelRate = channelMerchants.getUpgradeSplitRate().compareTo(BigDecimal.ZERO) == 0 ?
                        new BigDecimal(shareConfigMapper.getChannelUpgradeSplitRate()).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP) :
                        channelMerchants.getUpgradeSplitRate().divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
                break;
            case 2:
                channelRate = channelMerchants.getBellFirstSplitRate().compareTo(BigDecimal.ZERO) == 0 ?
                        new BigDecimal(shareConfigMapper.getChannelFirstBlockSplitRate()).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP) :
                        channelMerchants.getBellFirstSplitRate().divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
                break;
            case 3:
                channelRate = channelMerchants.getBellSecondSplitRate().compareTo(BigDecimal.ZERO) == 0 ?
                        new BigDecimal(shareConfigMapper.getChannelSecondBlockSplitRate()).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP) :
                        channelMerchants.getBellSecondSplitRate().divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
                break;
            default:
                channelRate = BigDecimal.ZERO;
                break;
        }
        return channelRate;
    }

    /**
     * 计算经纪人分成比例
     *
     * @param broker
     * @param type   0=正常项目 1=升级套餐 2=第一次加钟 3=第二次加钟
     * @return 分成比例（0.3）
     * @Date 2025 3月 31 14:10
     */
    private BigDecimal getBrokerRate(Broker broker, Integer type) {
        BigDecimal brokerRate;
        switch (type) {
            case 0:
                brokerRate = broker.getSplitRate().compareTo(BigDecimal.ZERO) == 0 ?
                        new BigDecimal(shareConfigMapper.getBrokerSplitRate()).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP) :
                        broker.getSplitRate().divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
                break;
            case 1:
                brokerRate = broker.getUpgradeSplitRate().compareTo(BigDecimal.ZERO) == 0 ?
                        new BigDecimal(shareConfigMapper.getBrokerUpgradeSplitRate()).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP) :
                        broker.getUpgradeSplitRate().divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
                break;
            case 2:
                brokerRate = broker.getBellFirstSplitRate().compareTo(BigDecimal.ZERO) == 0 ?
                        new BigDecimal(shareConfigMapper.getBrokerFirstBlockSplitRate()).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP) :
                        broker.getBellFirstSplitRate().divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
                break;
            case 3:
                brokerRate = broker.getBellSecondSplitRate().compareTo(BigDecimal.ZERO) == 0 ?
                        new BigDecimal(shareConfigMapper.getBrokerSecondBlockSplitRate()).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP) :
                        broker.getBellSecondSplitRate().divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
                break;
            default:
                brokerRate = BigDecimal.ZERO;
                break;
        }
        return brokerRate;
    }


    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public ApiRestResponse<Integer> userAppraiseOrder(Long userId, UserAppraiseOrderVo appraiseVo) {
        //UserItemOrder userItemOrder = userItemOrderMapper.selectOne(new LambdaQueryWrapper<UserItemOrder>()
        //        .eq(UserItemOrder::getOrderNo, appraiseVo.getOrderNo()));
        UserItemOrder userItemOrder = userItemOrderMapper.selectOneByOrderNo(appraiseVo.getOrderNo());

        if (CheckEmptyUtil.isEmpty(userItemOrder)) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.ORDER_EMPTY);
        }
        if (!userItemOrder.getOrderStatus().equals(OrderConstants.ORDER_STATUS_PENDING_EVALUATION)) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.CANT_CANCEL_APPRAISE);
        }
        UserAppraise insertUserAppraise = new UserAppraise();
        insertUserAppraise.setOrderNo(userItemOrder.getOrderNo());
        insertUserAppraise.setUserId(userId);
        insertUserAppraise.setTid(userItemOrder.getTid());
        insertUserAppraise.setItemId(userItemOrder.getItemId());
        insertUserAppraise.setItemName(userItemOrder.getItemName());
        insertUserAppraise.setItemPicture(userItemOrder.getItemPicture());
        insertUserAppraise.setItemTime(userItemOrder.getItemTime());
        insertUserAppraise.setItemCount(userItemOrder.getOrderNum());
        insertUserAppraise.setItemPrice(userItemOrder.getOrderTotalPrice());
        insertUserAppraise.setCommentText(appraiseVo.getCommentText());
        insertUserAppraise.setSatisfaction(appraiseVo.getSatisfaction());
        insertUserAppraise.setCommentPicture(appraiseVo.getCommentPicture());
        userAppraiseMapper.insert(insertUserAppraise);
        //修改订单状态
        userItemOrder.setOrderStatus(OrderConstants.ORDER_STATUS_OVER);
        int update = userItemOrderMapper.updateById(userItemOrder);
        //TechnicianItemOrder technicianItemOrder = technicianItemOrderMapper.selectOne(new LambdaQueryWrapper<TechnicianItemOrder>().eq(TechnicianItemOrder::getOrderNo, appraiseVo.getOrderNo()));
        //technicianItemOrder.setOrderStatus(OrderConstants.ORDER_STATUS_OVER);
        //int update = technicianItemOrderMapper.updateById(technicianItemOrder);

        return ApiRestResponse.success(update);
    }

    @Override
    public ApiRestResponse<Integer> userDeleteOrder(UserDeleteOrderVo deleteVo) {
        return ApiRestResponse.success(userItemOrderMapper.delete(new LambdaQueryWrapper<UserItemOrder>().eq(UserItemOrder::getOrderNo, deleteVo.getOrderNo())));
    }

    @Override
    public ApiRestResponse<UserUpgradeOrderDetailResponseVo> userUpgradeOrderDetail(Long userId, UserUpgradeOrderDetailVo upgradeOrderDetailVo) {
        UserUpgradeOrderDetailResponseVo vo = new UserUpgradeOrderDetailResponseVo();
        //UserItemOrder userItemOrder = userItemOrderMapper.selectOne(new LambdaQueryWrapper<UserItemOrder>()
        //        .eq(UserItemOrder::getOrderNo, upgradeOrderDetailVo.getOrderNo()));
        UserItemOrder userItemOrder = userItemOrderMapper.selectOneByOrderNo(upgradeOrderDetailVo.getOrderNo());

        if (CheckEmptyUtil.isEmpty(userItemOrder)) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.ORDER_EMPTY);
        }
        if (!userItemOrder.getOrderStatus().equals(OrderConstants.ORDER_STATUS_PENDING_START) &&
                !userItemOrder.getOrderStatus().equals(OrderConstants.ORDER_STATUS_PENDING_END)) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.CANT_UPGRADE);
        }
        int isVip = userMemberMapper.selectCount(new LambdaQueryWrapper<UserMember>().eq(UserMember::getUserId, userId)).intValue();

        CreateOrderResponseVo sumItem = sumItem(upgradeOrderDetailVo.getItemSpecsId(), userItemOrder.getOrderNum(), isVip, NumberConstants.ZERO_CONSTANTS);

        vo.setItemId(upgradeOrderDetailVo.getItemId());
        vo.setItemSpecsName(sumItem.getItemSpecsName());
        vo.setItemMainPicture(sumItem.getItemMainPicture());
        vo.setItemSpecsPrice(sumItem.getItemSpecsPrice());
        vo.setItemOldPrice(userItemOrder.getOrderItemPrice());
        vo.setItemNewPrice(sumItem.getItemPrice());
        vo.setDifferencePrice(sumItem.getItemPrice().subtract(userItemOrder.getOrderItemPrice()));
        vo.setItemNum(userItemOrder.getOrderNum());

        return ApiRestResponse.success(vo);
    }

    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public ApiRestResponse userUpgradeOrder(User user, UserUpgradeOrderVo upgradeOrderVo) throws Exception {
        //原订单
        //UserItemOrder oldUserItemOrder = userItemOrderMapper.selectOne(new LambdaQueryWrapper<UserItemOrder>()
        //        .eq(UserItemOrder::getOrderNo, upgradeOrderVo.getOrderNo()));
        UserItemOrder oldUserItemOrder = userItemOrderMapper.selectOneByOrderNo(upgradeOrderVo.getOrderNo());

        if (CheckEmptyUtil.isEmpty(oldUserItemOrder)) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.ORDER_EMPTY);
        }
        if (!oldUserItemOrder.getOrderStatus().equals(OrderConstants.ORDER_STATUS_PENDING_START) &&
                !oldUserItemOrder.getOrderStatus().equals(OrderConstants.ORDER_STATUS_PENDING_END)) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.CANT_UPGRADE);
        }
        int isVip = userMemberMapper.selectCount(new LambdaQueryWrapper<UserMember>().eq(UserMember::getUserId, user.getId())).intValue();

        CreateOrderResponseVo sumItem = sumItem(upgradeOrderVo.getItemSpecsId(), oldUserItemOrder.getOrderNum(), isVip, NumberConstants.ZERO_CONSTANTS);

        ItemSpecs itemSpecs = itemSpecsMapper.selectById(upgradeOrderVo.getItemSpecsId());
        Item item = !CheckEmptyUtil.isEmpty(itemSpecs) ? itemMapper.selectById(itemSpecs.getItemId()) : itemMapper.selectById(upgradeOrderVo.getItemSpecsId());
        //差价
        BigDecimal needPayPrice = sumItem.getItemPrice().subtract(oldUserItemOrder.getOrderItemPrice());
        //总价
        BigDecimal payTotalPrice = sumItem.getItemPrice();
        String orderNo = RandomUtils.getOrderNo();
        UserItemOrder insertUserItemOrder = new UserItemOrder();
        insertUserItemOrder.setPartnerOrderNo(upgradeOrderVo.getOrderNo());
        insertUserItemOrder.setOrderNo(orderNo);
        insertUserItemOrder.setUserId(user.getId());
        insertUserItemOrder.setTid(oldUserItemOrder.getTid());
        insertUserItemOrder.setItemId(upgradeOrderVo.getItemId());
        insertUserItemOrder.setItemSpecsId(upgradeOrderVo.getItemSpecsId());
        insertUserItemOrder.setItemName(!CheckEmptyUtil.isEmpty(itemSpecs) ? itemSpecs.getItemSpecsName() : item.getItemName());
        insertUserItemOrder.setItemPicture(item.getItemMainPicture());
        insertUserItemOrder.setItemTime(!CheckEmptyUtil.isEmpty(itemSpecs) ? itemSpecs.getItemSpecsTime() * oldUserItemOrder.getOrderNum() : item.getItemTime() * oldUserItemOrder.getOrderNum());
        insertUserItemOrder.setAddressId(oldUserItemOrder.getAddressId());
        insertUserItemOrder.setAddressUserName(oldUserItemOrder.getAddressUserName());
        insertUserItemOrder.setAddressTel(oldUserItemOrder.getAddressTel());
        insertUserItemOrder.setAddressDetail(oldUserItemOrder.getAddressDetail());
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        Date parse = simpleDateFormat.parse(oldUserItemOrder.getServiceTime());

        insertUserItemOrder.setServiceTime(simpleDateFormat.format(parse));
        insertUserItemOrder.setNeedPayPrice(needPayPrice);
        insertUserItemOrder.setOrderTotalPrice(payTotalPrice);
        insertUserItemOrder.setOrderItemPrice(sumItem.getItemSpecsPrice());
        insertUserItemOrder.setOrderFarePrice(BigDecimal.ZERO);
        insertUserItemOrder.setDiscountPrice(BigDecimal.ZERO);
        insertUserItemOrder.setIsUserCoupon(NumberConstants.ZERO_CONSTANTS);
        //insertUserItemOrder.setUserCouponId();
        insertUserItemOrder.setPlaceOrderTime(new Date());
        insertUserItemOrder.setOrderNum(oldUserItemOrder.getOrderNum());
        insertUserItemOrder.setIsOpenMembership(NumberConstants.ZERO_CONSTANTS);
        //insertUserItemOrder.setOpenMemberId();
        insertUserItemOrder.setOpenMemberPrice(BigDecimal.ZERO);
        insertUserItemOrder.setDistance(BigDecimal.ZERO);
        insertUserItemOrder.setModeTravel(oldUserItemOrder.getModeTravel());
        insertUserItemOrder.setOrderRemark(oldUserItemOrder.getOrderRemark());
        insertUserItemOrder.setOrderType(NumberConstants.TWO_CONSTANTS);
        insertUserItemOrder.setOrderStatus(OrderConstants.ORDER_STATUS_UPGRADES_NOT_PAID);
        userItemOrderMapper.insert(insertUserItemOrder);


        TechnicianItemOrder insertTechnicianItemOrder = new TechnicianItemOrder();
        insertTechnicianItemOrder.setPartnerOrderNo(upgradeOrderVo.getOrderNo());
        insertTechnicianItemOrder.setOrderNo(orderNo);
        insertTechnicianItemOrder.setUserId(user.getId());
        insertTechnicianItemOrder.setTid(oldUserItemOrder.getTid());
        insertTechnicianItemOrder.setItemId(upgradeOrderVo.getItemId());
        insertTechnicianItemOrder.setItemSpecsId(upgradeOrderVo.getItemSpecsId());
        insertTechnicianItemOrder.setItemName(!CheckEmptyUtil.isEmpty(itemSpecs) ? itemSpecs.getItemSpecsName() : item.getItemName());
        insertTechnicianItemOrder.setItemPicture(item.getItemMainPicture());
        insertTechnicianItemOrder.setItemTime(!CheckEmptyUtil.isEmpty(itemSpecs) ? itemSpecs.getItemSpecsTime() * oldUserItemOrder.getOrderNum() : item.getItemTime() * oldUserItemOrder.getOrderNum());
        insertTechnicianItemOrder.setAddressId(oldUserItemOrder.getAddressId());
        insertTechnicianItemOrder.setAddressUserName(oldUserItemOrder.getAddressUserName());
        insertTechnicianItemOrder.setAddressTel(oldUserItemOrder.getAddressTel());
        insertTechnicianItemOrder.setAddressDetail(oldUserItemOrder.getAddressDetail());
        insertTechnicianItemOrder.setServiceTime(simpleDateFormat.format(parse));
        insertTechnicianItemOrder.setNeedPayPrice(needPayPrice);
        insertTechnicianItemOrder.setOrderTotalPrice(payTotalPrice);
        insertTechnicianItemOrder.setOrderItemPrice(sumItem.getItemSpecsPrice());
        insertTechnicianItemOrder.setOrderFarePrice(BigDecimal.ZERO);
        insertTechnicianItemOrder.setDiscountPrice(BigDecimal.ZERO);
        insertTechnicianItemOrder.setIsUserCoupon(NumberConstants.ZERO_CONSTANTS);
        //insertUserItemOrder.setUserCouponId();
        insertTechnicianItemOrder.setPlaceOrderTime(new Date());
        insertTechnicianItemOrder.setOrderNum(oldUserItemOrder.getOrderNum());
        insertTechnicianItemOrder.setIsOpenMembership(NumberConstants.ZERO_CONSTANTS);
        //insertUserItemOrder.setOpenMemberId();
        insertTechnicianItemOrder.setOpenMemberPrice(BigDecimal.ZERO);
        insertTechnicianItemOrder.setDistance(BigDecimal.ZERO);
        insertTechnicianItemOrder.setModeTravel(oldUserItemOrder.getModeTravel());
        insertTechnicianItemOrder.setOrderRemark(oldUserItemOrder.getOrderRemark());
        insertTechnicianItemOrder.setOrderType(NumberConstants.TWO_CONSTANTS);
        insertTechnicianItemOrder.setOrderStatus(OrderConstants.ORDER_STATUS_UPGRADES_NOT_PAID);
        technicianItemOrderMapper.insert(insertTechnicianItemOrder);


        Message message = new Message();
        message.setUserId(user.getId());
        message.setOrderNo(orderNo);
        message.setMessageTitle("您有一条待支付订单");
        message.setMessageComment("您有一条待支付订单");
        messageMapper.insert(message);

        PayOrderRequestVo request = new PayOrderRequestVo();
        request.setUser(user);
        request.setOrderNo(orderNo);
        request.setPayType(upgradeOrderVo.getPayType());
        request.setWxType(upgradeOrderVo.getWxType());
        request.setReturnUrl(upgradeOrderVo.getReturnUrl());
        request.setQuitUrl(upgradeOrderVo.getQuitUrl());
        return upgradePayOrder(request);
    }

    @Override
    public ApiRestResponse<UserBellOrderDetailResponseVo> userBellOrderDetail(Long userId, UserBellOrderDetailVo userBellOrderDetailVo) {
        UserBellOrderDetailResponseVo vo = new UserBellOrderDetailResponseVo();
        //UserItemOrder userItemOrder = userItemOrderMapper.selectOne(new LambdaQueryWrapper<UserItemOrder>()
        //        .eq(UserItemOrder::getOrderNo, userBellOrderDetailVo.getOrderNo()));
        UserItemOrder userItemOrder = userItemOrderMapper.selectOneByOrderNo(userBellOrderDetailVo.getOrderNo());

        if (CheckEmptyUtil.isEmpty(userItemOrder)) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.ORDER_EMPTY);
        }
        if (!userItemOrder.getOrderStatus().equals(OrderConstants.ORDER_STATUS_PENDING_START) &&
                !userItemOrder.getOrderStatus().equals(OrderConstants.ORDER_STATUS_PENDING_END)) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.CANT_UPGRADE);
        }
        int isVip = userMemberMapper.selectCount(new LambdaQueryWrapper<UserMember>().eq(UserMember::getUserId, userId)).intValue();

        CreateOrderResponseVo sumItem = sumBellItem(userBellOrderDetailVo.getItemSpecsId(), userItemOrder.getOrderNum(), isVip, NumberConstants.ZERO_CONSTANTS);

        vo.setItemId(userBellOrderDetailVo.getItemId());
        vo.setItemSpecsId(userBellOrderDetailVo.getItemSpecsId());
        vo.setItemSpecsName(sumItem.getItemSpecsName());
        vo.setItemMainPicture(sumItem.getItemMainPicture());
        vo.setItemSpecsPrice(sumItem.getItemSpecsPrice());
        //vo.setItemPrice(sumItem.getItemPrice());
        vo.setItemNum(userItemOrder.getOrderNum());
        CreateOrderResponseVo createOrderResponseVo = sumCoupon(userBellOrderDetailVo.getIsUserCoupon(), userBellOrderDetailVo.getUserCouponId());
        vo.setCouponName(createOrderResponseVo.getCouponName());
        vo.setCouponPrice(createOrderResponseVo.getCouponDiscountPrice());
        vo.setTid(userItemOrder.getTid());
        vo.setTotalPayPrice(sumItem.getItemSpecsPrice().subtract(createOrderResponseVo.getCouponDiscountPrice()));
        vo.setTotalDiscountPrice(createOrderResponseVo.getCouponDiscountPrice().add(sumItem.getItemDiscountPrice()));

        return ApiRestResponse.success(vo);
    }

    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public ApiRestResponse userBellOrder(User user, UserBellOrderVo userBellOrderVo) throws Exception {
        //原订单
        //UserItemOrder oldUserItemOrder = userItemOrderMapper.selectOne(new LambdaQueryWrapper<UserItemOrder>()
        //        .eq(UserItemOrder::getOrderNo, userBellOrderVo.getOrderNo()));
        UserItemOrder oldUserItemOrder = userItemOrderMapper.selectOneByOrderNo(userBellOrderVo.getOrderNo());

        if (CheckEmptyUtil.isEmpty(oldUserItemOrder)) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.ORDER_EMPTY);
        }
        if (!oldUserItemOrder.getOrderStatus().equals(OrderConstants.ORDER_STATUS_PENDING_START) &&
                !oldUserItemOrder.getOrderStatus().equals(OrderConstants.ORDER_STATUS_PENDING_END)) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.CANT_BELL);
        }
        int isVip = userMemberMapper.selectCount(new LambdaQueryWrapper<UserMember>().eq(UserMember::getUserId, user.getId())).intValue();

        CreateOrderResponseVo sumItem = sumBellItem(userBellOrderVo.getItemSpecsId(), oldUserItemOrder.getOrderNum(), isVip, NumberConstants.ZERO_CONSTANTS);
        CreateOrderResponseVo createOrderResponseVo = sumCoupon(userBellOrderVo.getIsUserCoupon(), userBellOrderVo.getUserCouponId());
        ClockItemSpecs clockItemSpecs = clockItemSpecsMapper.selectById(userBellOrderVo.getItemSpecsId());
        //ItemSpecs itemSpecs = itemSpecsMapper.selectById(userBellOrderVo.getItemSpecsId());
        ClockItem clockItem = !CheckEmptyUtil.isEmpty(clockItemSpecs) ? clockItemMapper.selectById(clockItemSpecs.getClockItemId()) : clockItemMapper.selectById(userBellOrderVo.getItemSpecsId());
        //总价
        BigDecimal payTotalPrice = sumItem.getItemSpecsPrice();
        payTotalPrice = payTotalPrice.subtract(createOrderResponseVo.getCouponDiscountPrice());
        String orderNo = RandomUtils.getOrderNo();
        UserItemOrder insertUserItemOrder = new UserItemOrder();
        insertUserItemOrder.setPartnerOrderNo(userBellOrderVo.getOrderNo());
        insertUserItemOrder.setOrderNo(orderNo);
        insertUserItemOrder.setUserId(user.getId());
        insertUserItemOrder.setTid(oldUserItemOrder.getTid());
        insertUserItemOrder.setItemId(userBellOrderVo.getItemId());
        insertUserItemOrder.setItemSpecsId(userBellOrderVo.getItemSpecsId());
        insertUserItemOrder.setItemName(!CheckEmptyUtil.isEmpty(clockItemSpecs) ? clockItemSpecs.getItemSpecsName() : clockItem.getItemName());
        insertUserItemOrder.setItemPicture(clockItem.getItemMainPicture());
        insertUserItemOrder.setItemTime(!CheckEmptyUtil.isEmpty(clockItemSpecs) ? clockItemSpecs.getItemSpecsTime() * oldUserItemOrder.getOrderNum() : clockItem.getItemTime() * oldUserItemOrder.getOrderNum());
        insertUserItemOrder.setAddressId(oldUserItemOrder.getAddressId());
        insertUserItemOrder.setAddressUserName(oldUserItemOrder.getAddressUserName());
        insertUserItemOrder.setAddressTel(oldUserItemOrder.getAddressTel());
        insertUserItemOrder.setAddressDetail(oldUserItemOrder.getAddressDetail());
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        Date parse = simpleDateFormat.parse(oldUserItemOrder.getServiceTime());

        insertUserItemOrder.setServiceTime(simpleDateFormat.format(parse));
        insertUserItemOrder.setNeedPayPrice(payTotalPrice);
        insertUserItemOrder.setOrderTotalPrice(payTotalPrice);
        insertUserItemOrder.setOrderItemPrice(sumItem.getItemSpecsPrice());
        insertUserItemOrder.setOrderFarePrice(BigDecimal.ZERO);
        insertUserItemOrder.setDiscountPrice(BigDecimal.ZERO);
        insertUserItemOrder.setIsUserCoupon(NumberConstants.ZERO_CONSTANTS);
        insertUserItemOrder.setUserCouponId(userBellOrderVo.getUserCouponId());
        insertUserItemOrder.setUserCouponPrice(sumCoupon(userBellOrderVo.getIsUserCoupon(), userBellOrderVo.getUserCouponId()).getCouponDiscountPrice());

        insertUserItemOrder.setPlaceOrderTime(new Date());
        insertUserItemOrder.setOrderNum(oldUserItemOrder.getOrderNum());
        insertUserItemOrder.setIsOpenMembership(NumberConstants.ZERO_CONSTANTS);
        //insertUserItemOrder.setOpenMemberId();
        insertUserItemOrder.setOpenMemberPrice(BigDecimal.ZERO);
        insertUserItemOrder.setDistance(BigDecimal.ZERO);
        insertUserItemOrder.setModeTravel(oldUserItemOrder.getModeTravel());
        insertUserItemOrder.setOrderRemark(oldUserItemOrder.getOrderRemark());
        insertUserItemOrder.setOrderType(NumberConstants.ONE_CONSTANTS);
        insertUserItemOrder.setOrderStatus(OrderConstants.ORDER_STATUS_BELL_NOT_PAID);
        userItemOrderMapper.insert(insertUserItemOrder);


        TechnicianItemOrder insertTechnicianItemOrder = new TechnicianItemOrder();
        insertTechnicianItemOrder.setPartnerOrderNo(userBellOrderVo.getOrderNo());
        insertTechnicianItemOrder.setOrderNo(orderNo);
        insertTechnicianItemOrder.setUserId(user.getId());
        insertTechnicianItemOrder.setTid(oldUserItemOrder.getTid());
        insertTechnicianItemOrder.setItemId(userBellOrderVo.getItemId());
        insertTechnicianItemOrder.setItemSpecsId(userBellOrderVo.getItemSpecsId());
        insertTechnicianItemOrder.setItemName(!CheckEmptyUtil.isEmpty(clockItemSpecs) ? clockItemSpecs.getItemSpecsName() : clockItem.getItemName());
        insertTechnicianItemOrder.setItemPicture(clockItem.getItemMainPicture());
        insertTechnicianItemOrder.setItemTime(!CheckEmptyUtil.isEmpty(clockItemSpecs) ? clockItemSpecs.getItemSpecsTime() * oldUserItemOrder.getOrderNum() : clockItem.getItemTime() * oldUserItemOrder.getOrderNum());
        insertTechnicianItemOrder.setAddressId(oldUserItemOrder.getAddressId());
        insertTechnicianItemOrder.setAddressUserName(oldUserItemOrder.getAddressUserName());
        insertTechnicianItemOrder.setAddressTel(oldUserItemOrder.getAddressTel());
        insertTechnicianItemOrder.setAddressDetail(oldUserItemOrder.getAddressDetail());
        insertTechnicianItemOrder.setServiceTime(simpleDateFormat.format(parse));
        insertTechnicianItemOrder.setNeedPayPrice(payTotalPrice);
        insertTechnicianItemOrder.setOrderTotalPrice(payTotalPrice);
        insertTechnicianItemOrder.setOrderItemPrice(sumItem.getItemSpecsPrice());
        insertTechnicianItemOrder.setOrderFarePrice(BigDecimal.ZERO);
        insertTechnicianItemOrder.setDiscountPrice(BigDecimal.ZERO);
        insertTechnicianItemOrder.setIsUserCoupon(NumberConstants.ZERO_CONSTANTS);
        insertTechnicianItemOrder.setUserCouponId(userBellOrderVo.getUserCouponId());
        insertTechnicianItemOrder.setUserCouponPrice(sumCoupon(userBellOrderVo.getIsUserCoupon(), userBellOrderVo.getUserCouponId()).getCouponDiscountPrice());

        insertTechnicianItemOrder.setPlaceOrderTime(new Date());
        insertTechnicianItemOrder.setOrderNum(oldUserItemOrder.getOrderNum());
        insertTechnicianItemOrder.setIsOpenMembership(NumberConstants.ZERO_CONSTANTS);
        //insertUserItemOrder.setOpenMemberId();
        insertTechnicianItemOrder.setOpenMemberPrice(BigDecimal.ZERO);
        insertTechnicianItemOrder.setDistance(BigDecimal.ZERO);
        insertTechnicianItemOrder.setModeTravel(oldUserItemOrder.getModeTravel());
        insertTechnicianItemOrder.setOrderRemark(oldUserItemOrder.getOrderRemark());
        insertTechnicianItemOrder.setOrderType(NumberConstants.ONE_CONSTANTS);
        insertTechnicianItemOrder.setOrderStatus(OrderConstants.ORDER_STATUS_BELL_NOT_PAID);
        technicianItemOrderMapper.insert(insertTechnicianItemOrder);


        Message message = new Message();
        message.setUserId(user.getId());
        message.setOrderNo(orderNo);
        message.setMessageTitle("您有一条待支付订单");
        message.setMessageComment("您有一条待支付订单");
        messageMapper.insert(message);

        PayOrderRequestVo request = new PayOrderRequestVo();
        request.setUser(user);
        request.setOrderNo(orderNo);
        request.setPayType(userBellOrderVo.getPayType());
        request.setWxType(userBellOrderVo.getWxType());
        request.setReturnUrl(userBellOrderVo.getReturnUrl());
        request.setQuitUrl(userBellOrderVo.getQuitUrl());
        return bellPayOrder(request);

    }

    @Override
    public ApiRestResponse bellPayOrder(PayOrderRequestVo requestVo) throws Exception {
        User user = requestVo.getUser();
        //UserItemOrder userItemOrder = userItemOrderMapper.selectOne(new LambdaQueryWrapper<UserItemOrder>()
        //        .eq(UserItemOrder::getOrderNo, requestVo.getOrderNo()));
        UserItemOrder userItemOrder = userItemOrderMapper.selectOneByOrderNo(requestVo.getOrderNo());

        if (!userItemOrder.getOrderStatus().equals(OrderConstants.ORDER_STATUS_BELL_NOT_PAID)) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.ORDER_IS_PAY);
        }

        if (requestVo.getPayType().equals(PayConstants.BALANCE)) {
            //余额支付
            if (user.getUserBalance().compareTo(BigDecimal.ZERO) <= 0 || userItemOrder.getNeedPayPrice().compareTo(user.getUserBalance()) > 0) {
                throw new ErrorCodeException(ErrorCodeExceptionEnum.BALANCE_NOT_ENOUGH);
            }
            //扣除用户余额
            //添加消费记录
            //修改订单状态
            //删除系统消息
            //修改技师时间状态
            Integer subBalance = userMapper.subBalance(user.getId(), userItemOrder.getNeedPayPrice());
            if (subBalance == 0) {
                throw new ErrorCodeException(ErrorCodeExceptionEnum.ABNORMAL_OPERATION);
            }
            UserConsumeDetail userConsumeDetail = new UserConsumeDetail();
            userConsumeDetail.setUserId(user.getId());
            userConsumeDetail.setOrderNo(requestVo.getOrderNo());
            userConsumeDetail.setConsumptionPrice(userItemOrder.getNeedPayPrice());
            userConsumeDetail.setConsumptionType(CommonConstants.CONSUMPTION_REDUCE);
            userConsumeDetail.setConsumptionDescribe("购买" + userItemOrder.getItemName());
            userConsumeDetailMapper.insert(userConsumeDetail);

            bellUpdateOrder(userItemOrder.getOrderNo(), requestVo.getPayType());


            return ApiRestResponse.success();
        } else if (requestVo.getPayType().equals(PayConstants.WX)) {
            if (requestVo.getWxType().equals(PayConstants.JSAPI_TYPE)) {
                if (CheckEmptyUtil.isEmpty(user.getOpenId())) {
                    throw new ErrorCodeException(ErrorCodeExceptionEnum.NOT_BIND_WX);
                }
            }
            //微信支付
            WeChatCreateOrderVO createOrderVO = new WeChatCreateOrderVO();
            createOrderVO.setPayType(requestVo.getWxType());
            createOrderVO.setTotalPrice(userItemOrder.getNeedPayPrice().multiply(new BigDecimal(100)));
            createOrderVO.setOutTradeNo(requestVo.getOrderNo());
            createOrderVO.setDescription("加钟支付" + userItemOrder.getItemName());
            createOrderVO.setNotifyUrl(wxPayEntity.ProjectIP + "/api/wechat/bellNotify");
            createOrderVO.setOpenId(userMapper.selectById(user.getId()).getOpenId());
            SettleInfo settleInfo = new SettleInfo();
            settleInfo.setProfit_sharing(false);
            createOrderVO.setSettleInfo(settleInfo);
            log.info("微信支付入参数：[{}]", createOrderVO);
            Map<String, String> order = wechatPayService.createOrder(createOrderVO);
            return ApiRestResponse.success(order);

        } else if (requestVo.getPayType().equals(PayConstants.ZFB)) {
            if (!CheckEmptyUtil.isEmpty(userItemOrder.getZfbPayParam())) {
                return ApiRestResponse.success(userItemOrder.getZfbPayParam());
            } else {
                //支付宝支付
                String pay = alipayService.pay(requestVo.getWxType(), "加钟支付" + userItemOrder.getItemName(), requestVo.getOrderNo(), userItemOrder.getNeedPayPrice().toString(), requestVo.getReturnUrl(), requestVo.getQuitUrl(), alipayEntity.getNotifyIp() + "/api/alipay/bellNotify");
                userItemOrderMapper.insertZfbInfo(userItemOrder.getOrderNo(), pay);
                return ApiRestResponse.success(pay);
            }
        } else {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.PAY_TYPE_ERROR);
        }
    }

    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public void closeOrder() {
        //查询待接单订单
        List<UserItemOrder> userItemOrders = userItemOrderMapper.selectList(new LambdaQueryWrapper<UserItemOrder>()
                .eq(UserItemOrder::getOrderStatus, OrderConstants.ORDER_STATUS_PENDING_ACCEPTANCE));
        Integer technicianTakeOrderTime = Integer.parseInt(orderDictConfigMapper.getTechnicianTakeOrderTime());
        if (!CheckEmptyUtil.isEmpty(userItemOrders)) {
            userItemOrders.forEach(userItemOrder -> {
                if (new Date().after(DateUtil.offsetMinute(userItemOrder.getPayTime(), technicianTakeOrderTime))) {
                    //修改订单状态
                    userItemOrder.setOrderStatus(OrderConstants.ORDER_STATUS_CANCELLED);
                    userItemOrderMapper.updateById(userItemOrder);
                    technicianItemOrderMapper.updateStatus(userItemOrder.getOrderNo(), OrderConstants.ORDER_STATUS_CANCELLED);
                    TechnicianItemOrder technicianItemOrder = technicianItemOrderMapper.selectOne(new LambdaQueryWrapper<TechnicianItemOrder>()
                            .eq(TechnicianItemOrder::getOrderNo, userItemOrder.getOrderNo()));
                    try {
                        technicianItemOrderService.refundUser(technicianItemOrder,userItemOrder.getOrderTotalPrice());
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                }
            });
        }
    }

    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public void closeNotPayOrderStatus() {
        List<UserItemOrder> userItemOrders = userItemOrderMapper.selectList(new LambdaQueryWrapper<UserItemOrder>()
                .in(UserItemOrder::getOrderStatus, OrderConstants.ORDER_STATUS_PENDING_PAYMENT, OrderConstants.ORDER_STATUS_BELL_NOT_PAID, OrderConstants.ORDER_STATUS_UPGRADES_NOT_PAID)
        );
        if (!CheckEmptyUtil.isEmpty(userItemOrders)) {
            userItemOrders.forEach(userItemOrder -> {
                if (new Date().after(DateUtil.offsetMinute(userItemOrder.getPlaceOrderTime(), 10))) {
                    //修改订单状态
                    userItemOrder.setOrderStatus(OrderConstants.ORDER_STATUS_CANCELLED);
                    userItemOrder.setZfbPayParam(null);
                    userItemOrderMapper.updateById(userItemOrder);
                    technicianItemOrderMapper.updateStatus(userItemOrder.getOrderNo(), OrderConstants.ORDER_STATUS_CANCELLED);
                }

            });
        }
    }

    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public ApiRestResponse userUpgradeOrderCancelPay(String orderNo) {
        List<UserItemOrder> userItemOrder = userItemOrderMapper.selectList(new LambdaQueryWrapper<UserItemOrder>()
                .eq(UserItemOrder::getPartnerOrderNo, orderNo)
                .eq(UserItemOrder::getOrderType, NumberConstants.TWO_CONSTANTS)
                .eq(UserItemOrder::getOrderStatus, OrderConstants.ORDER_STATUS_UPGRADES_NOT_PAID));
        if (CheckEmptyUtil.isEmpty(userItemOrder)) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.ORDER_EMPTY);
        }
        int i = 0;
        for (UserItemOrder itemOrder : userItemOrder) {
            //修改订单状态
            userItemOrderMapper.updateOrder(itemOrder.getOrderNo(), OrderConstants.ORDER_STATUS_CANCELLED);
            i = technicianItemOrderMapper.updateStatus(itemOrder.getOrderNo(), OrderConstants.ORDER_STATUS_CANCELLED);
        }

        return ApiRestResponse.success(i);

    }

    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public ApiRestResponse bellOrderCancelPay(String orderNo) {
        List<UserItemOrder> userItemOrder = userItemOrderMapper.selectList(new LambdaQueryWrapper<UserItemOrder>()
                .eq(UserItemOrder::getPartnerOrderNo, orderNo)
                .eq(UserItemOrder::getOrderType, NumberConstants.ONE_CONSTANTS)
                .eq(UserItemOrder::getOrderStatus, OrderConstants.ORDER_STATUS_BELL_NOT_PAID));
        if (CheckEmptyUtil.isEmpty(userItemOrder)) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.ORDER_EMPTY);
        }
        int i = 0;
        for (UserItemOrder itemOrder : userItemOrder) {
            //修改订单状态
            userItemOrderMapper.updateOrder(itemOrder.getOrderNo(), OrderConstants.ORDER_STATUS_CANCELLED);
            i = technicianItemOrderMapper.updateStatus(itemOrder.getOrderNo(), OrderConstants.ORDER_STATUS_CANCELLED);
        }

        return ApiRestResponse.success(i);
    }


    @Override
    public void voiceTechnicianToTakeOrder() throws Exception {
        List<TechnicianItemOrder> technicianItemOrders = technicianItemOrderMapper.selectList(new LambdaQueryWrapper<TechnicianItemOrder>()
                .eq(TechnicianItemOrder::getOrderStatus, OrderConstants.ORDER_STATUS_PENDING_ACCEPTANCE));
        if (!CheckEmptyUtil.isEmpty(technicianItemOrders)) {
            for (TechnicianItemOrder technicianItemOrder : technicianItemOrders) {
                if (new Date().after(DateUtil.offsetMinute(technicianItemOrder.getPayTime(), 5)) && technicianItemOrder.getIsNotTakeOrderNotify() == 0) {
                    //通知技师
                    voiceTechnician(technicianItemOrder.getTid(), voiceTemplateConfigMapper.selectOneData("reminders"), technicianItemOrder.getOrderNo());
                    technicianItemOrderMapper.updateTakeOrderNotify(technicianItemOrder.getOrderNo());
                }

            }
        }
    }

    @Override
    public void voiceTechnicianToEnd() throws Exception {
        List<TechnicianItemOrder> technicianItemOrders = technicianItemOrderMapper.selectList(new LambdaQueryWrapper<TechnicianItemOrder>()
                .eq(TechnicianItemOrder::getOrderStatus, OrderConstants.ORDER_STATUS_PENDING_END)
                .eq(TechnicianItemOrder::getOrderType, 0));
        String technicianServiceOverTone = dictConfigMapper.selectValue("technician_service_over_tone");
        if (!CheckEmptyUtil.isEmpty(technicianItemOrders)) {
            for (TechnicianItemOrder technicianItemOrder : technicianItemOrders) {
                Integer orderTotalServiceTime = sumOrderTotalServiceTime(technicianItemOrder.getOrderNo());
                if (orderTotalServiceTime > 0) {
                    //距离服务结束时间前五分钟
                    if (new Date().after(DateUtil.offsetMinute(technicianItemOrder.getStartServiceTime(), orderTotalServiceTime - 5)) && technicianItemOrder.getIsNotify() == 0) {
                        //通知技师
                        voiceTechnician(technicianItemOrder.getTid(), voiceTemplateConfigMapper.selectOneData("order_over"), technicianItemOrder.getOrderNo());
                        MessageVo technicianPlaceOrderMessage = new MessageVo();
                        technicianPlaceOrderMessage.setMessage("订单还有五分钟结束");
                        technicianPlaceOrderMessage.setOrderNo(technicianItemOrder.getOrderNo());
                        technicianPlaceOrderMessage.setNotifyTime(new Date());
                        technicianPlaceOrderMessage.setType(NumberConstants.FOUR_CONSTANTS);
                        technicianPlaceOrderMessage.setVoiceUrl(technicianServiceOverTone);
                        //websocket发送消息到技师
                        new WebSocketServer().appointSending(JSON.toJSONString(technicianPlaceOrderMessage), technicianItemOrder.getTid().toString());
                        technicianItemOrderMapper.updateOrderNotify(technicianItemOrder.getOrderNo());
                        Thread.sleep(100L);
                    }
                }

            }
        }
    }

    private void refundPrice(String orderNo, Long userId, BigDecimal totalPrice, Integer isOpenVip, BigDecimal openVipPrice, String payType) {
        //退款金额
        BigDecimal refundPrice = isOpenVip == 1 ? totalPrice.subtract(openVipPrice) : totalPrice;
        //退款
        if (payType.equals(PayConstants.WX)) {
            WeChatRefundVO refundVO = new WeChatRefundVO();
            refundVO.setOut_refund_no(RandomUtils.getOrderNo());
            refundVO.setOut_trade_no(orderNo);
            WeChatRefundVO.amount amount = refundVO.new amount();
            amount.setTotal(totalPrice.multiply(PayConstants.WX_PAY_CONVERT).intValue());
            amount.setRefund(refundPrice.multiply(PayConstants.WX_PAY_CONVERT).intValue());
            refundVO.setAmount(amount);
            log.info("退款入参:{}", JSON.toJSONString(refundVO));
            WeChatRefundReturnVO weChatRefundReturnVO = wechatPayService.refundOrder(refundVO);
            log.info("退款结果:{}", JSON.toJSONString(weChatRefundReturnVO));
            if (!"SUCCESS".equals(weChatRefundReturnVO.getStatus()) && !"PROCESSING".equals(weChatRefundReturnVO.getStatus())) {
                throw new ErrorCodeException(ErrorCodeExceptionEnum.REFUND_ERROR);
            }
        } else {
            // 将订单总金额退还到用户余额
            Integer i = userMapper.addBalance(userId, refundPrice);
            if (i <= 0) {
                throw new ErrorCodeException(ErrorCodeExceptionEnum.REFUND_ERROR);
            }
            // 添加消费记录
            UserConsumeDetail consumptionDetails = new UserConsumeDetail();
            consumptionDetails.setUserId(userId);
            consumptionDetails.setOrderNo(orderNo);
            consumptionDetails.setConsumptionType(CommonConstants.CONSUMPTION_ADD);
            consumptionDetails.setConsumptionDescribe("订单:" + orderNo + "退款");
            consumptionDetails.setConsumptionPrice(refundPrice);
            userConsumeDetailMapper.insert(consumptionDetails);
        }


    }

    @Override
    public void bellUpdateOrder(String orderNo, String payType) {
        //UserItemOrder userItemOrder = userItemOrderMapper.selectOne(new LambdaQueryWrapper<UserItemOrder>()
        //        .eq(UserItemOrder::getOrderNo, orderNo));
        UserItemOrder userItemOrder = userItemOrderMapper.selectOneByOrderNo(orderNo);

        //UserItemOrder partnerUserItemOrder = userItemOrderMapper.selectOne(new LambdaQueryWrapper<UserItemOrder>()
        //        .eq(UserItemOrder::getOrderNo, userItemOrder.getPartnerOrderNo()));
        UserItemOrder partnerUserItemOrder = userItemOrderMapper.selectOneByOrderNo(userItemOrder.getPartnerOrderNo());

        userItemOrder.setOrderStatus(partnerUserItemOrder.getOrderStatus());
        userItemOrder.setPayType(payType);
        userItemOrder.setPayTime(new Date());
        userItemOrder.setZfbPayParam(null);
        userItemOrderMapper.updateById(userItemOrder);
        TechnicianItemOrder technicianItemOrder = technicianItemOrderMapper.selectOne(new LambdaQueryWrapper<TechnicianItemOrder>().eq(TechnicianItemOrder::getOrderNo, orderNo));
        technicianItemOrder.setOrderStatus(partnerUserItemOrder.getOrderStatus());
        technicianItemOrder.setPayType(payType);
        technicianItemOrder.setPayTime(new Date());
        technicianItemOrderMapper.updateById(technicianItemOrder);
        //修改优惠券状态
        if (userItemOrder.getIsUserCoupon().equals(NumberConstants.ONE_CONSTANTS)) {
            userCouponMapper.updateUserCouponStatus(userItemOrder.getUserCouponId(), CommonConstants.USERCOUPON_USER);
        }

        clockItemMapper.updateSales(userItemOrder.getItemId(), userItemOrder.getOrderNum());
        //technicianMapper.updateSales(userItemOrder.getTid(), userItemOrder.getOrderNum());
    }

    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public void technicianOrderException() throws IOException, InterruptedException {
        List<TechnicianItemOrder> technicianItemOrders = technicianItemOrderMapper.selectStopOrderExceptionList();

        if (!CheckEmptyUtil.isEmpty(technicianItemOrders)) {
            String backendExpectionTone = dictConfigMapper.selectValue("backend_expection_tone");
            for (TechnicianItemOrder technicianItemOrder : technicianItemOrders) {
                if (new Date().after(DateUtil.offsetMinute(technicianItemOrder.getStopServiceTime(), 10)) &&
                        new Date().before(DateUtil.offsetMinute(technicianItemOrder.getStopServiceTime(), 15))) {
                    String userLocation = gaoDeUtil.geoCode(technicianItemOrder.getAddressDetail());
                    Technician technician = technicianMapper.selectById(technicianItemOrder.getTid());
                    String distance = MathDistanceUtil.getDistance(userLocation, technician.getLongitude() + "," + technician.getLatitude(), 2);
                    if (new BigDecimal(distance).compareTo(new BigDecimal(100)) < 0 && technicianItemOrder.getIsException() == 0) {
                        //修改订单状态
                        technicianItemOrderMapper.updateOrderException(technicianItemOrder.getOrderNo());
                        //给后台通知异常订单
                        BackendOrderNotify backendOrderNotify = new BackendOrderNotify();
                        backendOrderNotify.setOrderNo(technicianItemOrder.getOrderNo());
                        backendOrderNotify.setTechnicianName(technician.getTechnicianName());
                        backendOrderNotify.setNotifyType(NumberConstants.ZERO_CONSTANTS);
                        User user = userMapper.selectById(technicianItemOrder.getUserId());
                        backendOrderNotify.setUserName(user.getUserNikeName());
                        backendOrderNotifyMapper.insert(backendOrderNotify);
                        //添加后台通知表
                        MessageVo messageVo = new MessageVo();
                        messageVo.setMessage("你有一笔的异常订单, 请及时处理");
                        messageVo.setOrderNo(technicianItemOrder.getOrderNo());
                        messageVo.setNotifyTime(new Date());
                        messageVo.setType(NumberConstants.ONE_CONSTANTS);
                        messageVo.setVoiceUrl(backendExpectionTone);
                        //websocket发送消息到后台
                        new WebSocketServer().appointSending(JSON.toJSONString(messageVo), "0");

                        Thread.sleep(100L);

                    }
                }
            }
        }
    }

    @Override
    public ApiRestResponse upgradePayOrder(PayOrderRequestVo requestVo) throws Exception {
        User user = requestVo.getUser();
        //UserItemOrder userItemOrder = userItemOrderMapper.selectOne(new LambdaQueryWrapper<UserItemOrder>()
        //        .eq(UserItemOrder::getOrderNo, requestVo.getOrderNo()));
        UserItemOrder userItemOrder = userItemOrderMapper.selectOneByOrderNo(requestVo.getOrderNo());
        if (!userItemOrder.getOrderStatus().equals(OrderConstants.ORDER_STATUS_UPGRADES_NOT_PAID)) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.ORDER_IS_PAY);
        }

        if (requestVo.getPayType().equals(PayConstants.BALANCE)) {
            //余额支付
            if (user.getUserBalance().compareTo(BigDecimal.ZERO) <= 0 || userItemOrder.getNeedPayPrice().compareTo(user.getUserBalance()) > 0) {
                throw new ErrorCodeException(ErrorCodeExceptionEnum.BALANCE_NOT_ENOUGH);
            }
            //扣除用户余额
            //添加消费记录
            //修改订单状态
            //删除系统消息
            //修改技师时间状态
            Integer subBalance = userMapper.subBalance(user.getId(), userItemOrder.getNeedPayPrice());
            if (subBalance == 0) {
                throw new ErrorCodeException(ErrorCodeExceptionEnum.ABNORMAL_OPERATION);
            }
            UserConsumeDetail userConsumeDetail = new UserConsumeDetail();
            userConsumeDetail.setUserId(user.getId());
            userConsumeDetail.setOrderNo(requestVo.getOrderNo());
            userConsumeDetail.setConsumptionPrice(userItemOrder.getNeedPayPrice());
            userConsumeDetail.setConsumptionType(CommonConstants.CONSUMPTION_REDUCE);
            userConsumeDetail.setConsumptionDescribe("购买" + userItemOrder.getItemName());
            userConsumeDetailMapper.insert(userConsumeDetail);

            upgradeUpdateOrder(userItemOrder.getOrderNo(), requestVo.getPayType());


            return ApiRestResponse.success();
        } else if (requestVo.getPayType().equals(PayConstants.WX)) {
            if (requestVo.getWxType().equals(PayConstants.JSAPI_TYPE)) {
                if (CheckEmptyUtil.isEmpty(user.getOpenId())) {
                    throw new ErrorCodeException(ErrorCodeExceptionEnum.NOT_BIND_WX);
                }
            }
            //微信支付
            WeChatCreateOrderVO createOrderVO = new WeChatCreateOrderVO();
            createOrderVO.setPayType(requestVo.getWxType());
            createOrderVO.setTotalPrice(userItemOrder.getNeedPayPrice().multiply(new BigDecimal(100)));
            createOrderVO.setOutTradeNo(requestVo.getOrderNo());
            createOrderVO.setDescription("升级套餐支付" + userItemOrder.getItemName());
            createOrderVO.setNotifyUrl(wxPayEntity.ProjectIP + "/api/wechat/upgradeNotify");
            createOrderVO.setOpenId(userMapper.selectById(user.getId()).getOpenId());
            SettleInfo settleInfo = new SettleInfo();
            settleInfo.setProfit_sharing(false);
            createOrderVO.setSettleInfo(settleInfo);
            log.info("微信支付入参数：[{}]", createOrderVO);
            Map<String, String> order = wechatPayService.createOrder(createOrderVO);
            return ApiRestResponse.success(order);

        } else if (requestVo.getPayType().equals(PayConstants.ZFB)) {
            if (!CheckEmptyUtil.isEmpty(userItemOrder.getZfbPayParam())) {
                return ApiRestResponse.success(userItemOrder.getZfbPayParam());
            } else {
                //支付宝支付
                String pay = alipayService.pay(requestVo.getWxType(), "升级套餐支付" + userItemOrder.getItemName(), requestVo.getOrderNo(), userItemOrder.getNeedPayPrice().toString(), requestVo.getReturnUrl(), requestVo.getQuitUrl(), alipayEntity.getNotifyIp() + "/api/alipay/upgradeNotify");
                userItemOrderMapper.insertZfbInfo(userItemOrder.getOrderNo(), pay);
                return ApiRestResponse.success(pay);
            }
        } else {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.PAY_TYPE_ERROR);
        }
    }

    /**
     * 计算项目总服务时长
     *
     * @param orderNo 订单编号
     * @return 总服务时长，单位分钟
     * @Date 2025 4月 08 14:23
     */
    @Override
    public Integer sumOrderTotalServiceTime(String orderNo) {
        Integer orderTotalServiceTime = NumberConstants.ZERO_CONSTANTS;
        UserItemOrder userItemOrder = userItemOrderMapper.selectOneByOrderNo(orderNo);
        if (!CheckEmptyUtil.isEmpty(userItemOrder)) {
            orderTotalServiceTime = userItemOrder.getItemTime();
            //计算升级套餐
            List<Integer> upgradeTotalServiceTime = new ArrayList<>();
            List<UserItemOrder> userItemOrders = userItemOrderMapper.selectList(new LambdaQueryWrapper<UserItemOrder>()
                    .eq(UserItemOrder::getPartnerOrderNo, orderNo)
                    .eq(UserItemOrder::getOrderType, NumberConstants.TWO_CONSTANTS)
                    .notIn(UserItemOrder::getOrderStatus, OrderConstants.ORDER_STATUS_UPGRADES_NOT_PAID, OrderConstants.ORDER_STATUS_CANCELLED));
            if (!CheckEmptyUtil.isEmpty(userItemOrders)) {
                userItemOrders.forEach(item -> {
                    upgradeTotalServiceTime.add(item.getItemTime());
                });
                orderTotalServiceTime = Math.toIntExact(upgradeTotalServiceTime.stream().mapToInt((s) -> s).summaryStatistics().getSum());
            }
            //计算加钟套餐
            List<Integer> bellTotalServiceTime = new ArrayList<>();
            List<UserItemOrder> userItemOrders1 = userItemOrderMapper.selectList(new LambdaQueryWrapper<UserItemOrder>()
                    .eq(UserItemOrder::getPartnerOrderNo, orderNo)
                    .eq(UserItemOrder::getOrderType, NumberConstants.ONE_CONSTANTS)
                    .notIn(UserItemOrder::getOrderStatus, OrderConstants.ORDER_STATUS_BELL_NOT_PAID, OrderConstants.ORDER_STATUS_CANCELLED)
            );
            if (!CheckEmptyUtil.isEmpty(userItemOrders1)) {
                userItemOrders1.forEach(item -> {
                    bellTotalServiceTime.add(item.getItemTime());
                });
                orderTotalServiceTime = orderTotalServiceTime + (Math.toIntExact(bellTotalServiceTime.stream().mapToInt((s) -> s).summaryStatistics().getSum()));
            }
        }
        return orderTotalServiceTime;

    }


    @Override
    public void upgradeUpdateOrder(String orderNo, String payType) {
        //UserItemOrder userItemOrder = userItemOrderMapper.selectOne(new LambdaQueryWrapper<UserItemOrder>()
        //        .eq(UserItemOrder::getOrderNo, orderNo));
        UserItemOrder userItemOrder = userItemOrderMapper.selectOneByOrderNo(orderNo);
        //UserItemOrder partnerUserItemOrder = userItemOrderMapper.selectOne(new LambdaQueryWrapper<UserItemOrder>()
        //        .eq(UserItemOrder::getOrderNo, userItemOrder.getPartnerOrderNo()));
        UserItemOrder partnerUserItemOrder = userItemOrderMapper.selectOneByOrderNo(userItemOrder.getPartnerOrderNo());
        userItemOrder.setOrderStatus(partnerUserItemOrder.getOrderStatus());
        userItemOrder.setPayType(payType);
        userItemOrder.setPayTime(new Date());
        userItemOrder.setZfbPayParam(null);
        userItemOrderMapper.updateById(userItemOrder);
        TechnicianItemOrder technicianItemOrder = technicianItemOrderMapper.selectOne(new LambdaQueryWrapper<TechnicianItemOrder>().eq(TechnicianItemOrder::getOrderNo, orderNo));
        technicianItemOrder.setOrderStatus(partnerUserItemOrder.getOrderStatus());
        technicianItemOrder.setPayType(payType);
        technicianItemOrder.setPayTime(new Date());
        technicianItemOrderMapper.updateById(technicianItemOrder);

        //更新项目销量
        itemMapper.updateSales(userItemOrder.getItemId(), userItemOrder.getOrderNum());
        //technicianMapper.updateSales(userItemOrder.getTid(), userItemOrder.getOrderNum());
        itemMapper.subSales(partnerUserItemOrder.getItemId(), partnerUserItemOrder.getOrderNum());

        //messageMapper.deleteMessage(orderNo);
        //SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        ////服务时间
        //Date serviceTime = simpleDateFormat.parse(userItemOrder.getServiceTime());
        ////项目完成时间
        //DateTime orderFinshTime = sumOrderFinishTime(simpleDateFormat, userItemOrder.getServiceTime(), userItemOrder.getItemTime());
        ////更新服务时间 状态为已被预约
        //technicianTimeMapper.updateTimeToTwo(userItemOrder.getTid(), simpleDateFormat.format(serviceTime));
        ////更新服务时间 到 服务结束时间+1小时 之内的时间为不可约状态
        //technicianTimeMapper.updateTimeToOne(userItemOrder.getTid(), simpleDateFormat.format(serviceTime), simpleDateFormat.format(orderFinshTime));
        //
    }

    private DateTime sumOrderFinishTime(SimpleDateFormat simpleDateFormat, String serviceTime, Integer itemTime) throws ParseException {
        //服务时间
        //String s = DateUtil.thisYear() + "-" + serviceTime;
        Date parse = simpleDateFormat.parse(serviceTime);
        DateTime dateTime = DateUtil.offsetMinute(parse, itemTime);
        return DateUtil.offsetHour(dateTime, 1);
    }


    private void parseStringToDate(String day, String time) {
        Date date = DateUtils.parseStringToDate(DateTime.now().year() + "-" + day + " " + time, "yyyy-MM-dd HH:mm");
        if (date.compareTo(DateUtils.addMinute(new Date(), 30)) < 0) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.TIME_LATER);
        }

    }

    /**
     * 计算加钟项目
     *
     * @param itemSpecsId
     * @param num
     * @param isVip
     * @return
     * @Date 2025 3月 11 12:13
     */
    private CreateOrderResponseVo sumBellItem(Long itemSpecsId, Integer num, Integer isVip, Integer isOpenVip) {
        CreateOrderResponseVo vo = new CreateOrderResponseVo();
        ClockItemSpecs clockItemSpecs = clockItemSpecsMapper.selectById(itemSpecsId);
        ClockItem clockItem = !CheckEmptyUtil.isEmpty(clockItemSpecs) ? clockItemMapper.selectById(clockItemSpecs.getClockItemId()) : clockItemMapper.selectById(itemSpecsId);

        if (!CheckEmptyUtil.isEmpty(clockItem)) {
            vo.setItemMainPicture(clockItem.getItemMainPicture());
            vo.setItemSpecsName(!CheckEmptyUtil.isEmpty(clockItemSpecs) ? clockItemSpecs.getItemSpecsName() : clockItem.getItemName());
            vo.setItemNum(num);

            BigDecimal itemPrice = !CheckEmptyUtil.isEmpty(clockItemSpecs) ? clockItemSpecs.getItemSpecsPrice() : clockItem.getItemPrice();
            BigDecimal itemMemberPrice = !CheckEmptyUtil.isEmpty(clockItemSpecs) ? clockItemSpecs.getItemSpecsMemberPrice() : clockItem.getItemMemberPrice();

            if (isVip == 0) {
                vo.setItemSpecsPrice(isOpenVip.equals(NumberConstants.ONE_CONSTANTS) ? itemMemberPrice.multiply(new BigDecimal(num)) : itemPrice.multiply(new BigDecimal(num)));
                vo.setItemDiscountPrice(isOpenVip.equals(NumberConstants.ONE_CONSTANTS) ? itemPrice.subtract(itemMemberPrice).multiply(new BigDecimal(num)) : BigDecimal.ZERO);
            } else {
                vo.setItemSpecsPrice(itemMemberPrice.multiply(new BigDecimal(num)));
                vo.setItemDiscountPrice((itemPrice.subtract(itemMemberPrice).multiply(new BigDecimal(num))));
            }

            vo.setItemPrice(itemPrice.multiply(new BigDecimal(num)));
            vo.setItemVipPrice(itemMemberPrice.multiply(new BigDecimal(num)));

            //vo.setItemDiscountPrice(itemPrice.subtract(itemMemberPrice.multiply(new BigDecimal(num))));
            vo.setServerTime(!CheckEmptyUtil.isEmpty(clockItemSpecs) ? clockItemSpecs.getItemSpecsTime() : clockItem.getItemTime());
        }

        return vo;
    }

    /**
     * 计算项目
     *
     * @param itemSpecsId
     * @param num
     * @param isVip
     * @return
     * @Date 2025 3月 11 12:13
     */
    private CreateOrderResponseVo sumItem(Long itemSpecsId, Integer num, Integer isVip, Integer isOpenVip) {
        CreateOrderResponseVo vo = new CreateOrderResponseVo();
        ItemSpecs itemSpecs = itemSpecsMapper.selectById(itemSpecsId);
        Item item = !CheckEmptyUtil.isEmpty(itemSpecs) ? itemMapper.selectById(itemSpecs.getItemId()) : itemMapper.selectById(itemSpecsId);

        if (!CheckEmptyUtil.isEmpty(item)) {
            vo.setItemMainPicture(item.getItemMainPicture());
            vo.setItemSpecsName(!CheckEmptyUtil.isEmpty(itemSpecs) ? itemSpecs.getItemSpecsName() : item.getItemName());
            vo.setItemNum(num);

            BigDecimal itemPrice = !CheckEmptyUtil.isEmpty(itemSpecs) ? itemSpecs.getItemSpecsPrice() : item.getItemPrice();
            BigDecimal itemMemberPrice = !CheckEmptyUtil.isEmpty(itemSpecs) ? itemSpecs.getItemSpecsMemberPrice() : item.getItemMemberPrice();

            if (isVip == 0) {
                vo.setItemSpecsPrice(isOpenVip.equals(NumberConstants.ONE_CONSTANTS) ? itemMemberPrice.multiply(new BigDecimal(num)) : itemPrice.multiply(new BigDecimal(num)));
                vo.setItemDiscountPrice(isOpenVip.equals(NumberConstants.ONE_CONSTANTS) ? itemPrice.subtract(itemMemberPrice).multiply(new BigDecimal(num)) : BigDecimal.ZERO);
            } else {
                vo.setItemSpecsPrice(itemMemberPrice.multiply(new BigDecimal(num)));
                vo.setItemDiscountPrice((itemPrice.subtract(itemMemberPrice).multiply(new BigDecimal(num))));
            }

            vo.setItemPrice(itemPrice.multiply(new BigDecimal(num)));
            vo.setItemVipPrice(itemMemberPrice.multiply(new BigDecimal(num)));
            vo.setItemTime(itemSpecs.getItemSpecsTime() * num);
            //vo.setItemDiscountPrice(itemPrice.subtract(itemMemberPrice.multiply(new BigDecimal(num))));
            vo.setServerTime(!CheckEmptyUtil.isEmpty(itemSpecs) ? itemSpecs.getItemSpecsTime() : item.getItemTime());
        }

        return vo;
    }

    /**
     * 计算会员
     *
     * @param isVip
     * @param itemSpecsPrice
     * @param itemSpecsMemberPrice
     * @return
     * @Date 2025 3月 11 12:25
     */
    private CreateOrderResponseVo sumVip(Integer isVip, BigDecimal itemSpecsPrice, BigDecimal itemSpecsMemberPrice) {
        CreateOrderResponseVo vo = new CreateOrderResponseVo();
        if (isVip == 0) {
            MemberConfig memberConfig = memberConfigMapper.selectOne(new LambdaQueryWrapper<MemberConfig>()
                    .orderByAsc(MemberConfig::getId)
                    .last(" limit 1"));
            vo.setVipId(memberConfig.getId());
            vo.setVipName(memberConfig.getMemberName());
            vo.setVipPrice(memberConfig.getMemberPrice());
            vo.setVipVipPrice(memberConfig.getMemberDiscountPrice());
            vo.setVipDiscountPrice(itemSpecsPrice.subtract(itemSpecsMemberPrice));
        }
        return vo;
    }

    /**
     * 计算优惠券
     *
     * @param userCouponId
     * @return
     * @Date 2025 3月 11 12:31
     */
    private CreateOrderResponseVo sumCoupon(Integer isUserCoupon, Long userCouponId) {
        CreateOrderResponseVo vo = new CreateOrderResponseVo();
        BigDecimal couponDiscountPrice = BigDecimal.ZERO;
        if (isUserCoupon.equals(NumberConstants.ONE_CONSTANTS)) {
            //使用优惠券
            UserCoupon userCoupon = userCouponMapper.selectById(userCouponId);
            if (!CheckEmptyUtil.isEmpty(userCoupon)) {
                CouponConfig couponConfig = couponConfigMapper.selectById(userCoupon.getCouponId());
                vo.setCouponName(couponConfig.getCouponName());
                couponDiscountPrice = couponConfig.getCouponSubtract();
            }
        }
        vo.setCouponDiscountPrice(couponDiscountPrice);
        return vo;
    }

    /**
     * 计算地址
     *
     * @param addressId
     * @return
     * @Date 2025 3月 11 12:36
     */
    private CreateOrderResponseVo sumAddress(Long addressId) {
        CreateOrderResponseVo vo = new CreateOrderResponseVo();
        UserAddress address = userAddressMapper.selectById(addressId);
        if (!CheckEmptyUtil.isEmpty(address)) {
            vo.setAddressName(address.getAddressName());
            vo.setAddressTel(address.getAddressTel());
            vo.setAddress(address.getAddress() + address.getAddressDetails());
        }
        return vo;
    }

    /**
     * 计算路费
     *
     * @param addressId
     * @param technician
     * @param technicianTimeId
     * @return
     * @throws ParseException
     * @Date 2025 3月 11 16:31
     */
    private CreateOrderResponseVo sumCarFare(Long addressId, Technician technician, Long technicianTimeId) throws ParseException {
        CreateOrderResponseVo vo = new CreateOrderResponseVo();

        //日间开始时间
        String dayStartTime;
        //日间结束时间
        String dayEndTime;
        //日间起步价
        BigDecimal dayStartPrice;
        //日间起步价外每公里多少钱
        BigDecimal dayPrePrice;
        //夜间起步价
        BigDecimal nightStartPrice;
        //夜间起步价外每公里多少钱
        BigDecimal nightPrePrice;
        //虚拟公里数
        BigDecimal dummyDistance;

        UserAddress address = userAddressMapper.selectById(addressId);
        if (CheckEmptyUtil.isEmpty(address)) {
            vo.setCarFare(BigDecimal.ZERO);
        } else {
            WSSsdrAddress wsSsdrAddress = AddressUtil.addressFormat(address.getAddress() + address.getAddressDetails());
            //城市
            String city = wsSsdrAddress.getCity();
            //省份
            String province = wsSsdrAddress.getProvince();
            //获取城市路费设置
            CityFareConfig cityFareConfig = cityFareConfigMapper.selectOneCity(city, province);
            if (CheckEmptyUtil.isEmpty(cityFareConfig)) {
                //获取全局配置
                CityFareGlobalConfig dayStartTimeGlobal = cityFareGlobalConfigMapper.selectOne(new LambdaQueryWrapper<CityFareGlobalConfig>().select(CityFareGlobalConfig::getValue).eq(CityFareGlobalConfig::getCode, "day_start_time"));
                CityFareGlobalConfig dayEndTimeGlobal = cityFareGlobalConfigMapper.selectOne(new LambdaQueryWrapper<CityFareGlobalConfig>().select(CityFareGlobalConfig::getValue).eq(CityFareGlobalConfig::getCode, "day_end_time"));
                CityFareGlobalConfig dayStartPriceGlobal = cityFareGlobalConfigMapper.selectOne(new LambdaQueryWrapper<CityFareGlobalConfig>().select(CityFareGlobalConfig::getValue).eq(CityFareGlobalConfig::getCode, "day_start_price"));
                CityFareGlobalConfig dayPrePriceGlobal = cityFareGlobalConfigMapper.selectOne(new LambdaQueryWrapper<CityFareGlobalConfig>().select(CityFareGlobalConfig::getValue).eq(CityFareGlobalConfig::getCode, "day_pre_price"));
                CityFareGlobalConfig nightStartPriceGlobal = cityFareGlobalConfigMapper.selectOne(new LambdaQueryWrapper<CityFareGlobalConfig>().select(CityFareGlobalConfig::getValue).eq(CityFareGlobalConfig::getCode, "night_start_price"));
                CityFareGlobalConfig nightPrePriceGlobal = cityFareGlobalConfigMapper.selectOne(new LambdaQueryWrapper<CityFareGlobalConfig>().select(CityFareGlobalConfig::getValue).eq(CityFareGlobalConfig::getCode, "night_pre_price"));
                CityFareGlobalConfig dummyDistance1 = cityFareGlobalConfigMapper.selectOne(new LambdaQueryWrapper<CityFareGlobalConfig>().select(CityFareGlobalConfig::getValue).eq(CityFareGlobalConfig::getCode, "dummy_distance"));
                dayStartTime = dayStartTimeGlobal.getValue();
                dayEndTime = dayEndTimeGlobal.getValue();
                dayStartPrice = new BigDecimal(dayStartPriceGlobal.getValue());
                dayPrePrice = new BigDecimal(dayPrePriceGlobal.getValue());
                nightStartPrice = new BigDecimal(nightStartPriceGlobal.getValue());
                nightPrePrice = new BigDecimal(nightPrePriceGlobal.getValue());
                dummyDistance = new BigDecimal(dummyDistance1.getValue());
            } else {
                dayStartTime = cityFareConfig.getDayStartTime();
                dayEndTime = cityFareConfig.getDayEndTime();
                dayStartPrice = cityFareConfig.getDayStartPrice();
                dayPrePrice = cityFareConfig.getDayPrePrice();
                nightStartPrice = cityFareConfig.getNightStartPrice();
                nightPrePrice = cityFareConfig.getNightPrePrice();
                dummyDistance = cityFareConfig.getDummyDistance();
            }

            //车费
            BigDecimal carFare = BigDecimal.ZERO;
            //获取服务时间的 时分秒
            TechnicianTime technicianTime = technicianTimeMapper.selectById(technicianTimeId);
            if (!CheckEmptyUtil.isEmpty(technicianTime)) {
                SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HH:mm");
                //判断服务时间是白天还是晚上时间
                boolean in = DateUtil.isIn(simpleDateFormat.parse(technicianTime.getTime()), simpleDateFormat.parse(dayStartTime), simpleDateFormat.parse(dayEndTime));
                if (in) {
                    //白天时间
                    log.info("当前为白天时间段");
                    Map<String, BigDecimal> map = sumFare(in, address.getAddress() + address.getAddressDetails(), technician, dayStartPrice, dayPrePrice, dummyDistance);
                    carFare = map.get("carFee");
                    vo.setDistance(map.get("distance"));
                } else {
                    //晚上时间
                    log.info("当前为晚上时间段");
                    Map<String, BigDecimal> map = sumFare(in, address.getAddress() + address.getAddressDetails(), technician, nightStartPrice, nightPrePrice, dummyDistance);
                    carFare = map.get("carFee");
                    vo.setDistance(map.get("distance"));
                }
            }


            vo.setCarFare(carFare);
        }
        return vo;
    }

    /**
     * 计算车费
     *
     * @param dayOrNight    true = 白天
     * @param address       用户服务地址
     * @param technician    技师对象
     * @param startPrice    起步价格
     * @param prePrice      每公里价格
     * @param dummyDistance 虚拟公里
     * @return
     * @Date 2025 3月 11 16:23
     */
    private Map<String, BigDecimal> sumFare(boolean dayOrNight, String address, Technician technician, BigDecimal startPrice, BigDecimal prePrice, BigDecimal dummyDistance) {

        Map<String, BigDecimal> map = new HashMap<>(2);
        //车费
        BigDecimal carFee;
        String userLongLat = gaoDeUtil.geoCode(address);
        String technicianLongLat = technician.getLongitude() + "," + technician.getLatitude();
        String distance = MathDistanceUtil.getDistance(userLongLat, technicianLongLat, 2);
        //用户和技师之间的距离 (单位：千米)
        BigDecimal distanceBig = new BigDecimal(distance).divide(new BigDecimal(1000), 2, RoundingMode.HALF_UP);
        //虚拟公里数
        distanceBig = distanceBig.add(dummyDistance);
        //技师免车费距离
        BigDecimal startDistance;
        //获取技师的免车费距离
        if (dayOrNight) {
            //白天
            startDistance = technician.getDayFreeTolls();
        } else {
            //晚上
            startDistance = technician.getNightFreeTolls();
        }
        if (distanceBig.compareTo(startDistance) <= 0) {
            //在起步距离之内，免费
            carFee = BigDecimal.ZERO;
        } else if (distanceBig.compareTo(startDistance) > 0) {
            //起步距离之内免费  起步距离之外每公里计算路费
            // 起步距离之外的路程
            BigDecimal subDistance = distanceBig.subtract(startDistance);
            // 求商 商几就有几个一公里
            BigDecimal divide = subDistance.divide(BigDecimal.ONE, 2, RoundingMode.HALF_UP);
            // 商小于1并且大于0 车费=起步价+超出一公里价格
            if (divide.compareTo(BigDecimal.ONE) <= 0 && divide.compareTo(BigDecimal.ZERO) > 0) {
                carFee = startPrice.add(prePrice);
            } else {
                // 商大于1 向上取整
                BigDecimal totalPrePrice = prePrice.multiply(divide).setScale(0, RoundingMode.HALF_UP);
                carFee = startPrice.add(totalPrePrice);
            }
        } else {
            carFee = BigDecimal.ZERO;
        }
        map.put("carFee", carFee);
        map.put("distance", distanceBig);
        return map;

    }
}
